tui_big_text/
big_text.rs

1use std::cmp::min;
2
3use derive_builder::Builder;
4use font8x8::UnicodeFonts;
5use ratatui_core::buffer::Buffer;
6use ratatui_core::layout::{Alignment, Rect};
7use ratatui_core::style::Style;
8use ratatui_core::text::{Line, StyledGrapheme};
9use ratatui_core::widgets::Widget;
10
11use crate::PixelSize;
12
13/// Displays one or more lines of text using 8x8 pixel characters.
14///
15/// The text is rendered using the [font8x8](https://crates.io/crates/font8x8) crate.
16///
17/// Using the `pixel_size` method, you can also chose, how 'big' a pixel should be. Currently a
18/// pixel of the 8x8 font can be represented by one full or half (horizontal/vertical/both)
19/// character cell of the terminal.
20///
21/// # Examples
22///
23/// ```rust
24/// use ratatui::prelude::*;
25/// use tui_big_text::{BigText, PixelSize};
26///
27/// BigText::builder()
28///     .pixel_size(PixelSize::Full)
29///     .style(Style::new().white())
30///     .lines(vec![
31///         "Hello".red().into(),
32///         "World".blue().into(),
33///         "=====".into(),
34///     ])
35///     .build();
36/// ```
37///
38/// Renders:
39///
40/// ```plain
41/// ██  ██           ███     ███
42/// ██  ██            ██      ██
43/// ██  ██   ████     ██      ██     ████
44/// ██████  ██  ██    ██      ██    ██  ██
45/// ██  ██  ██████    ██      ██    ██  ██
46/// ██  ██  ██        ██      ██    ██  ██
47/// ██  ██   ████    ████    ████    ████
48///
49/// ██   ██                  ███       ███
50/// ██   ██                   ██        ██
51/// ██   ██  ████   ██ ███    ██        ██
52/// ██ █ ██ ██  ██   ███ ██   ██     █████
53/// ███████ ██  ██   ██  ██   ██    ██  ██
54/// ███ ███ ██  ██   ██       ██    ██  ██
55/// ██   ██  ████   ████     ████    ███ ██
56///
57///  ███ ██  ███ ██  ███ ██  ███ ██  ███ ██
58/// ██ ███  ██ ███  ██ ███  ██ ███  ██ ███
59/// ```
60#[derive(Debug, Builder, Clone, PartialEq, Eq, Hash)]
61#[builder(build_fn(skip))]
62#[non_exhaustive]
63pub struct BigText<'a> {
64    /// The text to display
65    #[builder(default, setter(into))]
66    pub lines: Vec<Line<'a>>,
67
68    /// The style of the widget
69    ///
70    /// Defaults to `Style::default()`
71    #[builder(default, setter(into))]
72    pub style: Style,
73
74    /// The size of single glyphs
75    ///
76    /// Defaults to `PixelSize::default()` (=> PixelSize::Full)
77    #[builder(default)]
78    pub pixel_size: PixelSize,
79
80    /// The horizontal alignment of the text
81    ///
82    /// Defaults to `Alignment::default()` (=> Alignment::Left)
83    #[builder(default)]
84    pub alignment: Alignment,
85}
86
87impl BigText<'static> {
88    /// Create a new [`BigTextBuilder`] to configure a [`BigText`] widget.
89    pub fn builder() -> BigTextBuilder<'static> {
90        BigTextBuilder::default()
91    }
92}
93
94impl BigTextBuilder<'_> {
95    /// Set the alignment of the text.
96    pub fn left_aligned(&mut self) -> &mut Self {
97        self.alignment(Alignment::Left)
98    }
99
100    /// Set the alignment of the text.
101    pub fn right_aligned(&mut self) -> &mut Self {
102        self.alignment(Alignment::Right)
103    }
104
105    /// Set the alignment of the text.
106    pub fn centered(&mut self) -> &mut Self {
107        self.alignment(Alignment::Center)
108    }
109}
110
111impl<'a> BigTextBuilder<'a> {
112    /// Build the [`BigText`] widget.
113    pub fn build(&self) -> BigText<'a> {
114        BigText {
115            lines: self.lines.as_ref().cloned().unwrap_or_default(),
116            style: self.style.unwrap_or_default(),
117            pixel_size: self.pixel_size.unwrap_or_default(),
118            alignment: self.alignment.unwrap_or_default(),
119        }
120    }
121}
122
123impl Widget for BigText<'_> {
124    fn render(self, area: Rect, buf: &mut Buffer) {
125        let layout = layout(area, &self.pixel_size, self.alignment, &self.lines);
126        for (line, line_layout) in self.lines.iter().zip(layout) {
127            for (g, cell) in line.styled_graphemes(self.style).zip(line_layout) {
128                render_symbol(g, cell, buf, &self.pixel_size);
129            }
130        }
131    }
132}
133
134/// Chunk the area into as many x*y cells as possible returned as a 2D iterator of `Rect`s
135/// representing the rows of cells. The size of each cell depends on given font size
136fn layout<'a>(
137    area: Rect,
138    pixel_size: &PixelSize,
139    alignment: Alignment,
140    lines: &'a [Line<'a>],
141) -> impl IntoIterator<Item = impl IntoIterator<Item = Rect>> + 'a {
142    let (step_x, step_y) = pixel_size.pixels_per_cell();
143    let width = 8_u16.div_ceil(step_x);
144    let height = 8_u16.div_ceil(step_y);
145
146    (area.top()..area.bottom())
147        .step_by(height as usize)
148        .zip(lines.iter())
149        .map(move |(y, line)| {
150            let offset = get_alignment_offset(area.width, width, alignment, line);
151            (area.left() + offset..area.right())
152                .step_by(width as usize)
153                .map(move |x| {
154                    let width = min(area.right() - x, width);
155                    let height = min(area.bottom() - y, height);
156                    Rect::new(x, y, width, height)
157                })
158        })
159}
160
161fn get_alignment_offset<'a>(
162    area_width: u16,
163    letter_width: u16,
164    alignment: Alignment,
165    line: &'a Line<'a>,
166) -> u16 {
167    let big_line_width = line.width() as u16 * letter_width;
168    match alignment {
169        Alignment::Center => (area_width / 2).saturating_sub(big_line_width / 2),
170        Alignment::Right => area_width.saturating_sub(big_line_width),
171        Alignment::Left => 0,
172    }
173}
174
175/// Render a single grapheme into a cell by looking up the corresponding 8x8 bitmap in the
176/// `BITMAPS` array and setting the corresponding cells in the buffer.
177fn render_symbol(grapheme: StyledGrapheme, area: Rect, buf: &mut Buffer, pixel_size: &PixelSize) {
178    buf.set_style(area, grapheme.style);
179    let c = grapheme.symbol.chars().next().unwrap(); // TODO: handle multi-char graphemes
180    if let Some(glyph) = font8x8::BASIC_FONTS.get(c) {
181        render_glyph(glyph, area, buf, pixel_size);
182    }
183}
184
185/// Render a single 8x8 glyph into a cell by setting the corresponding cells in the buffer.
186fn render_glyph(glyph: [u8; 8], area: Rect, buf: &mut Buffer, pixel_size: &PixelSize) {
187    let (step_x, step_y) = pixel_size.pixels_per_cell();
188
189    let glyph_vertical_index = (0..glyph.len()).step_by(step_y as usize);
190    let glyph_horizontal_bit_selector = (0..8).step_by(step_x as usize);
191
192    for (y, row) in glyph_vertical_index.zip(area.rows()) {
193        for (x, col) in glyph_horizontal_bit_selector.clone().zip(row.columns()) {
194            buf[col].set_char(pixel_size.symbol_for_position(&glyph, y, x));
195        }
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use ratatui_core::style::Stylize;
202
203    use super::*;
204
205    #[test]
206    fn build() {
207        let lines = vec![Line::from(vec!["Hello".red(), "World".blue()])];
208        let style = Style::new().green();
209        let pixel_size = PixelSize::default();
210        let alignment = Alignment::Center;
211        assert_eq!(
212            BigText::builder()
213                .lines(lines.clone())
214                .style(style)
215                .alignment(Alignment::Center)
216                .build(),
217            BigText {
218                lines,
219                style,
220                pixel_size,
221                alignment,
222            }
223        );
224    }
225
226    #[test]
227    fn render_single_line() {
228        let big_text = BigText::builder()
229            .lines(vec![Line::from("SingleLine")])
230            .build();
231        let mut buf = Buffer::empty(Rect::new(0, 0, 80, 8));
232        big_text.render(buf.area, &mut buf);
233        let expected = Buffer::with_lines(vec![
234            " ████     ██                     ███            ████      ██                    ",
235            "██  ██                            ██             ██                             ",
236            "███      ███    █████    ███ ██   ██     ████    ██      ███    █████    ████   ",
237            " ███      ██    ██  ██  ██  ██    ██    ██  ██   ██       ██    ██  ██  ██  ██  ",
238            "   ███    ██    ██  ██  ██  ██    ██    ██████   ██   █   ██    ██  ██  ██████  ",
239            "██  ██    ██    ██  ██   █████    ██    ██       ██  ██   ██    ██  ██  ██      ",
240            " ████    ████   ██  ██      ██   ████    ████   ███████  ████   ██  ██   ████   ",
241            "                        █████                                                   ",
242        ]);
243        assert_eq!(buf, expected);
244    }
245
246    #[test]
247    fn render_truncated() {
248        let big_text = BigText::builder()
249            .lines(vec![Line::from("Truncated")])
250            .build();
251        let mut buf = Buffer::empty(Rect::new(0, 0, 70, 6));
252        big_text.render(buf.area, &mut buf);
253        let expected = Buffer::with_lines(vec![
254            "██████                                             █               ███",
255            "█ ██ █                                            ██                ██",
256            "  ██    ██ ███  ██  ██  █████    ████    ████    █████   ████       ██",
257            "  ██     ███ ██ ██  ██  ██  ██  ██  ██      ██    ██    ██  ██   █████",
258            "  ██     ██  ██ ██  ██  ██  ██  ██       █████    ██    ██████  ██  ██",
259            "  ██     ██     ██  ██  ██  ██  ██  ██  ██  ██    ██ █  ██      ██  ██",
260        ]);
261        assert_eq!(buf, expected);
262    }
263
264    #[test]
265    fn render_multiple_lines() {
266        let big_text = BigText::builder()
267            .lines(vec![Line::from("Multi"), Line::from("Lines")])
268            .build();
269        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 16));
270        big_text.render(buf.area, &mut buf);
271        let expected = Buffer::with_lines(vec![
272            "██   ██          ███       █      ██    ",
273            "███ ███           ██      ██            ",
274            "███████ ██  ██    ██     █████   ███    ",
275            "███████ ██  ██    ██      ██      ██    ",
276            "██ █ ██ ██  ██    ██      ██      ██    ",
277            "██   ██ ██  ██    ██      ██ █    ██    ",
278            "██   ██  ███ ██  ████      ██    ████   ",
279            "                                        ",
280            "████      ██                            ",
281            " ██                                     ",
282            " ██      ███    █████    ████    █████  ",
283            " ██       ██    ██  ██  ██  ██  ██      ",
284            " ██   █   ██    ██  ██  ██████   ████   ",
285            " ██  ██   ██    ██  ██  ██          ██  ",
286            "███████  ████   ██  ██   ████   █████   ",
287            "                                        ",
288        ]);
289        assert_eq!(buf, expected);
290    }
291
292    #[test]
293    fn render_widget_style() {
294        let big_text = BigText::builder()
295            .lines(vec![Line::from("Styled")])
296            .style(Style::new().bold())
297            .build();
298        let mut buf = Buffer::empty(Rect::new(0, 0, 48, 8));
299        big_text.render(buf.area, &mut buf);
300        let mut expected = Buffer::with_lines(vec![
301            " ████      █             ███               ███  ",
302            "██  ██    ██              ██                ██  ",
303            "███      █████  ██  ██    ██     ████       ██  ",
304            " ███      ██    ██  ██    ██    ██  ██   █████  ",
305            "   ███    ██    ██  ██    ██    ██████  ██  ██  ",
306            "██  ██    ██ █   █████    ██    ██      ██  ██  ",
307            " ████      ██       ██   ████    ████    ███ ██ ",
308            "                █████                           ",
309        ]);
310        expected.set_style(Rect::new(0, 0, 48, 8), Style::new().bold());
311        assert_eq!(buf, expected);
312    }
313
314    #[test]
315    fn render_line_style() {
316        let big_text = BigText::builder()
317            .lines(vec![
318                Line::from("Red".red()),
319                Line::from("Green".green()),
320                Line::from("Blue".blue()),
321            ])
322            .build();
323        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 24));
324        big_text.render(buf.area, &mut buf);
325        let mut expected = Buffer::with_lines(vec![
326            "██████             ███                  ",
327            " ██  ██             ██                  ",
328            " ██  ██  ████       ██                  ",
329            " █████  ██  ██   █████                  ",
330            " ██ ██  ██████  ██  ██                  ",
331            " ██  ██ ██      ██  ██                  ",
332            "███  ██  ████    ███ ██                 ",
333            "                                        ",
334            "  ████                                  ",
335            " ██  ██                                 ",
336            "██      ██ ███   ████    ████   █████   ",
337            "██       ███ ██ ██  ██  ██  ██  ██  ██  ",
338            "██  ███  ██  ██ ██████  ██████  ██  ██  ",
339            " ██  ██  ██     ██      ██      ██  ██  ",
340            "  █████ ████     ████    ████   ██  ██  ",
341            "                                        ",
342            "██████   ███                            ",
343            " ██  ██   ██                            ",
344            " ██  ██   ██    ██  ██   ████           ",
345            " █████    ██    ██  ██  ██  ██          ",
346            " ██  ██   ██    ██  ██  ██████          ",
347            " ██  ██   ██    ██  ██  ██              ",
348            "██████   ████    ███ ██  ████           ",
349            "                                        ",
350        ]);
351        expected.set_style(Rect::new(0, 0, 24, 8), Style::new().red());
352        expected.set_style(Rect::new(0, 8, 40, 8), Style::new().green());
353        expected.set_style(Rect::new(0, 16, 32, 8), Style::new().blue());
354        assert_eq!(buf, expected);
355    }
356
357    #[test]
358    fn render_half_height_single_line() {
359        let big_text = BigText::builder()
360            .pixel_size(PixelSize::HalfHeight)
361            .lines(vec![Line::from("SingleLine")])
362            .build();
363        let mut buf = Buffer::empty(Rect::new(0, 0, 80, 4));
364        big_text.render(buf.area, &mut buf);
365        let expected = Buffer::with_lines(vec![
366            "▄█▀▀█▄    ▀▀                     ▀██            ▀██▀      ▀▀                    ",
367            "▀██▄     ▀██    ██▀▀█▄  ▄█▀▀▄█▀   ██    ▄█▀▀█▄   ██      ▀██    ██▀▀█▄  ▄█▀▀█▄  ",
368            "▄▄ ▀██    ██    ██  ██  ▀█▄▄██    ██    ██▀▀▀▀   ██  ▄█   ██    ██  ██  ██▀▀▀▀  ",
369            " ▀▀▀▀    ▀▀▀▀   ▀▀  ▀▀  ▄▄▄▄█▀   ▀▀▀▀    ▀▀▀▀   ▀▀▀▀▀▀▀  ▀▀▀▀   ▀▀  ▀▀   ▀▀▀▀   ",
370        ]);
371        assert_eq!(buf, expected);
372    }
373
374    #[test]
375    fn render_half_height_truncated() {
376        let big_text = BigText::builder()
377            .pixel_size(PixelSize::HalfHeight)
378            .lines(vec![Line::from("Truncated")])
379            .build();
380        let mut buf = Buffer::empty(Rect::new(0, 0, 70, 3));
381        big_text.render(buf.area, &mut buf);
382        let expected = Buffer::with_lines(vec![
383            "█▀██▀█                                            ▄█               ▀██",
384            "  ██    ▀█▄█▀█▄ ██  ██  ██▀▀█▄  ▄█▀▀█▄   ▀▀▀█▄   ▀██▀▀  ▄█▀▀█▄   ▄▄▄██",
385            "  ██     ██  ▀▀ ██  ██  ██  ██  ██  ▄▄  ▄█▀▀██    ██ ▄  ██▀▀▀▀  ██  ██",
386        ]);
387        assert_eq!(buf, expected);
388    }
389
390    #[test]
391    fn render_half_height_multiple_lines() {
392        let big_text = BigText::builder()
393            .pixel_size(PixelSize::HalfHeight)
394            .lines(vec![Line::from("Multi"), Line::from("Lines")])
395            .build();
396        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 8));
397        big_text.render(buf.area, &mut buf);
398        let expected = Buffer::with_lines(vec![
399            "██▄ ▄██          ▀██      ▄█      ▀▀    ",
400            "███████ ██  ██    ██     ▀██▀▀   ▀██    ",
401            "██ ▀ ██ ██  ██    ██      ██ ▄    ██    ",
402            "▀▀   ▀▀  ▀▀▀ ▀▀  ▀▀▀▀      ▀▀    ▀▀▀▀   ",
403            "▀██▀      ▀▀                            ",
404            " ██      ▀██    ██▀▀█▄  ▄█▀▀█▄  ▄█▀▀▀▀  ",
405            " ██  ▄█   ██    ██  ██  ██▀▀▀▀   ▀▀▀█▄  ",
406            "▀▀▀▀▀▀▀  ▀▀▀▀   ▀▀  ▀▀   ▀▀▀▀   ▀▀▀▀▀   ",
407        ]);
408        assert_eq!(buf, expected);
409    }
410
411    #[test]
412    fn render_half_height_widget_style() {
413        let big_text = BigText::builder()
414            .pixel_size(PixelSize::HalfHeight)
415            .lines(vec![Line::from("Styled")])
416            .style(Style::new().bold())
417            .build();
418        let mut buf = Buffer::empty(Rect::new(0, 0, 48, 4));
419        big_text.render(buf.area, &mut buf);
420        let mut expected = Buffer::with_lines(vec![
421            "▄█▀▀█▄    ▄█             ▀██               ▀██  ",
422            "▀██▄     ▀██▀▀  ██  ██    ██    ▄█▀▀█▄   ▄▄▄██  ",
423            "▄▄ ▀██    ██ ▄  ▀█▄▄██    ██    ██▀▀▀▀  ██  ██  ",
424            " ▀▀▀▀      ▀▀   ▄▄▄▄█▀   ▀▀▀▀    ▀▀▀▀    ▀▀▀ ▀▀ ",
425        ]);
426        expected.set_style(Rect::new(0, 0, 48, 4), Style::new().bold());
427        assert_eq!(buf, expected);
428    }
429
430    #[test]
431    fn render_half_height_line_style() {
432        let big_text = BigText::builder()
433            .pixel_size(PixelSize::HalfHeight)
434            .lines(vec![
435                Line::from("Red".red()),
436                Line::from("Green".green()),
437                Line::from("Blue".blue()),
438            ])
439            .build();
440        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 12));
441        big_text.render(buf.area, &mut buf);
442        let mut expected = Buffer::with_lines(vec![
443            "▀██▀▀█▄            ▀██                  ",
444            " ██▄▄█▀ ▄█▀▀█▄   ▄▄▄██                  ",
445            " ██ ▀█▄ ██▀▀▀▀  ██  ██                  ",
446            "▀▀▀  ▀▀  ▀▀▀▀    ▀▀▀ ▀▀                 ",
447            " ▄█▀▀█▄                                 ",
448            "██      ▀█▄█▀█▄ ▄█▀▀█▄  ▄█▀▀█▄  ██▀▀█▄  ",
449            "▀█▄ ▀██  ██  ▀▀ ██▀▀▀▀  ██▀▀▀▀  ██  ██  ",
450            "  ▀▀▀▀▀ ▀▀▀▀     ▀▀▀▀    ▀▀▀▀   ▀▀  ▀▀  ",
451            "▀██▀▀█▄  ▀██                            ",
452            " ██▄▄█▀   ██    ██  ██  ▄█▀▀█▄          ",
453            " ██  ██   ██    ██  ██  ██▀▀▀▀          ",
454            "▀▀▀▀▀▀   ▀▀▀▀    ▀▀▀ ▀▀  ▀▀▀▀           ",
455        ]);
456        expected.set_style(Rect::new(0, 0, 24, 4), Style::new().red());
457        expected.set_style(Rect::new(0, 4, 40, 4), Style::new().green());
458        expected.set_style(Rect::new(0, 8, 32, 4), Style::new().blue());
459        assert_eq!(buf, expected);
460    }
461
462    #[test]
463    fn render_half_width_single_line() {
464        let big_text = BigText::builder()
465            .pixel_size(PixelSize::HalfWidth)
466            .lines(vec![Line::from("SingleLine")])
467            .build();
468        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 8));
469        big_text.render(buf.area, &mut buf);
470        let expected = Buffer::with_lines(vec![
471            "▐█▌  █          ▐█      ██   █          ",
472            "█ █              █      ▐▌              ",
473            "█▌  ▐█  ██▌ ▐█▐▌ █  ▐█▌ ▐▌  ▐█  ██▌ ▐█▌ ",
474            "▐█   █  █ █ █ █  █  █ █ ▐▌   █  █ █ █ █ ",
475            " ▐█  █  █ █ █ █  █  ███ ▐▌ ▌ █  █ █ ███ ",
476            "█ █  █  █ █ ▐██  █  █   ▐▌▐▌ █  █ █ █   ",
477            "▐█▌ ▐█▌ █ █   █ ▐█▌ ▐█▌ ███▌▐█▌ █ █ ▐█▌ ",
478            "            ██▌                         ",
479        ]);
480        assert_eq!(buf, expected);
481    }
482
483    #[test]
484    fn render_half_width_truncated() {
485        let big_text = BigText::builder()
486            .pixel_size(PixelSize::HalfWidth)
487            .lines(vec![Line::from("Truncated")])
488            .build();
489        let mut buf = Buffer::empty(Rect::new(0, 0, 35, 6));
490        big_text.render(buf.area, &mut buf);
491        let expected = Buffer::with_lines(vec![
492            "███                      ▐       ▐█",
493            "▌█▐                      █        █",
494            " █  █▐█ █ █ ██▌ ▐█▌ ▐█▌ ▐██ ▐█▌   █",
495            " █  ▐█▐▌█ █ █ █ █ █   █  █  █ █ ▐██",
496            " █  ▐▌▐▌█ █ █ █ █   ▐██  █  ███ █ █",
497            " █  ▐▌  █ █ █ █ █ █ █ █  █▐ █   █ █",
498        ]);
499        assert_eq!(buf, expected);
500    }
501
502    #[test]
503    fn render_half_width_multiple_lines() {
504        let big_text = BigText::builder()
505            .pixel_size(PixelSize::HalfWidth)
506            .lines(vec![Line::from("Multi"), Line::from("Lines")])
507            .build();
508        let mut buf = Buffer::empty(Rect::new(0, 0, 20, 16));
509        big_text.render(buf.area, &mut buf);
510        let expected = Buffer::with_lines(vec![
511            "█ ▐▌    ▐█   ▐   █  ",
512            "█▌█▌     █   █      ",
513            "███▌█ █  █  ▐██ ▐█  ",
514            "███▌█ █  █   █   █  ",
515            "█▐▐▌█ █  █   █   █  ",
516            "█ ▐▌█ █  █   █▐  █  ",
517            "█ ▐▌▐█▐▌▐█▌  ▐▌ ▐█▌ ",
518            "                    ",
519            "██   █              ",
520            "▐▌                  ",
521            "▐▌  ▐█  ██▌ ▐█▌ ▐██ ",
522            "▐▌   █  █ █ █ █ █   ",
523            "▐▌ ▌ █  █ █ ███ ▐█▌ ",
524            "▐▌▐▌ █  █ █ █     █ ",
525            "███▌▐█▌ █ █ ▐█▌ ██▌ ",
526            "                    ",
527        ]);
528        assert_eq!(buf, expected);
529    }
530
531    #[test]
532    fn render_half_width_widget_style() {
533        let big_text = BigText::builder()
534            .pixel_size(PixelSize::HalfWidth)
535            .lines(vec![Line::from("Styled")])
536            .style(Style::new().bold())
537            .build();
538        let mut buf = Buffer::empty(Rect::new(0, 0, 24, 8));
539        big_text.render(buf.area, &mut buf);
540        let mut expected = Buffer::with_lines(vec![
541            "▐█▌  ▐      ▐█       ▐█ ",
542            "█ █  █       █        █ ",
543            "█▌  ▐██ █ █  █  ▐█▌   █ ",
544            "▐█   █  █ █  █  █ █ ▐██ ",
545            " ▐█  █  █ █  █  ███ █ █ ",
546            "█ █  █▐ ▐██  █  █   █ █ ",
547            "▐█▌  ▐▌   █ ▐█▌ ▐█▌ ▐█▐▌",
548            "        ██▌             ",
549        ]);
550        expected.set_style(Rect::new(0, 0, 24, 8), Style::new().bold());
551        assert_eq!(buf, expected);
552    }
553
554    #[test]
555    fn render_half_width_line_style() {
556        let big_text = BigText::builder()
557            .pixel_size(PixelSize::HalfWidth)
558            .lines(vec![
559                Line::from("Red".red()),
560                Line::from("Green".green()),
561                Line::from("Blue".blue()),
562            ])
563            .build();
564        let mut buf = Buffer::empty(Rect::new(0, 0, 20, 24));
565        big_text.render(buf.area, &mut buf);
566        let mut expected = Buffer::with_lines(vec![
567            "███      ▐█         ",
568            "▐▌▐▌      █         ",
569            "▐▌▐▌▐█▌   █         ",
570            "▐██ █ █ ▐██         ",
571            "▐▌█ ███ █ █         ",
572            "▐▌▐▌█   █ █         ",
573            "█▌▐▌▐█▌ ▐█▐▌        ",
574            "                    ",
575            " ██                 ",
576            "▐▌▐▌                ",
577            "█   █▐█ ▐█▌ ▐█▌ ██▌ ",
578            "█   ▐█▐▌█ █ █ █ █ █ ",
579            "█ █▌▐▌▐▌███ ███ █ █ ",
580            "▐▌▐▌▐▌  █   █   █ █ ",
581            " ██▌██  ▐█▌ ▐█▌ █ █ ",
582            "                    ",
583            "███ ▐█              ",
584            "▐▌▐▌ █              ",
585            "▐▌▐▌ █  █ █ ▐█▌     ",
586            "▐██  █  █ █ █ █     ",
587            "▐▌▐▌ █  █ █ ███     ",
588            "▐▌▐▌ █  █ █ █       ",
589            "███ ▐█▌ ▐█▐▌▐█▌     ",
590            "                    ",
591        ]);
592        expected.set_style(Rect::new(0, 0, 12, 8), Style::new().red());
593        expected.set_style(Rect::new(0, 8, 20, 8), Style::new().green());
594        expected.set_style(Rect::new(0, 16, 16, 8), Style::new().blue());
595        assert_eq!(buf, expected);
596    }
597
598    #[test]
599    fn render_quadrant_size_single_line() {
600        let big_text = BigText::builder()
601            .pixel_size(PixelSize::Quadrant)
602            .lines(vec![Line::from("SingleLine")])
603            .build();
604        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 4));
605        big_text.render(buf.area, &mut buf);
606        let expected = Buffer::with_lines(vec![
607            "▟▀▙  ▀          ▝█      ▜▛   ▀          ",
608            "▜▙  ▝█  █▀▙ ▟▀▟▘ █  ▟▀▙ ▐▌  ▝█  █▀▙ ▟▀▙ ",
609            "▄▝█  █  █ █ ▜▄█  █  █▀▀ ▐▌▗▌ █  █ █ █▀▀ ",
610            "▝▀▘ ▝▀▘ ▀ ▀ ▄▄▛ ▝▀▘ ▝▀▘ ▀▀▀▘▝▀▘ ▀ ▀ ▝▀▘ ",
611        ]);
612        assert_eq!(buf, expected);
613    }
614
615    #[test]
616    fn render_quadrant_size_truncated() {
617        let big_text = BigText::builder()
618            .pixel_size(PixelSize::Quadrant)
619            .lines(vec![Line::from("Truncated")])
620            .build();
621        let mut buf = Buffer::empty(Rect::new(0, 0, 35, 3));
622        big_text.render(buf.area, &mut buf);
623        let expected = Buffer::with_lines(vec![
624            "▛█▜                      ▟       ▝█",
625            " █  ▜▟▜▖█ █ █▀▙ ▟▀▙ ▝▀▙ ▝█▀ ▟▀▙ ▗▄█",
626            " █  ▐▌▝▘█ █ █ █ █ ▄ ▟▀█  █▗ █▀▀ █ █",
627        ]);
628        assert_eq!(buf, expected);
629    }
630
631    #[test]
632    fn render_quadrant_size_multiple_lines() {
633        let big_text = BigText::builder()
634            .pixel_size(PixelSize::Quadrant)
635            .lines(vec![Line::from("Multi"), Line::from("Lines")])
636            .build();
637        let mut buf = Buffer::empty(Rect::new(0, 0, 20, 8));
638        big_text.render(buf.area, &mut buf);
639        let expected = Buffer::with_lines(vec![
640            "█▖▟▌    ▝█   ▟   ▀  ",
641            "███▌█ █  █  ▝█▀ ▝█  ",
642            "█▝▐▌█ █  █   █▗  █  ",
643            "▀ ▝▘▝▀▝▘▝▀▘  ▝▘ ▝▀▘ ",
644            "▜▛   ▀              ",
645            "▐▌  ▝█  █▀▙ ▟▀▙ ▟▀▀ ",
646            "▐▌▗▌ █  █ █ █▀▀ ▝▀▙ ",
647            "▀▀▀▘▝▀▘ ▀ ▀ ▝▀▘ ▀▀▘ ",
648        ]);
649        assert_eq!(buf, expected);
650    }
651
652    #[test]
653    fn render_quadrant_size_widget_style() {
654        let big_text = BigText::builder()
655            .pixel_size(PixelSize::Quadrant)
656            .lines(vec![Line::from("Styled")])
657            .style(Style::new().bold())
658            .build();
659        let mut buf = Buffer::empty(Rect::new(0, 0, 24, 4));
660        big_text.render(buf.area, &mut buf);
661        let mut expected = Buffer::with_lines(vec![
662            "▟▀▙  ▟      ▝█       ▝█ ",
663            "▜▙  ▝█▀ █ █  █  ▟▀▙ ▗▄█ ",
664            "▄▝█  █▗ ▜▄█  █  █▀▀ █ █ ",
665            "▝▀▘  ▝▘ ▄▄▛ ▝▀▘ ▝▀▘ ▝▀▝▘",
666        ]);
667        expected.set_style(Rect::new(0, 0, 24, 4), Style::new().bold());
668        assert_eq!(buf, expected);
669    }
670
671    #[test]
672    fn render_quadrant_size_line_style() {
673        let big_text = BigText::builder()
674            .pixel_size(PixelSize::Quadrant)
675            .lines(vec![
676                Line::from("Red".red()),
677                Line::from("Green".green()),
678                Line::from("Blue".blue()),
679            ])
680            .build();
681        let mut buf = Buffer::empty(Rect::new(0, 0, 20, 12));
682        big_text.render(buf.area, &mut buf);
683        let mut expected = Buffer::with_lines(vec![
684            "▜▛▜▖     ▝█         ",
685            "▐▙▟▘▟▀▙ ▗▄█         ",
686            "▐▌▜▖█▀▀ █ █         ",
687            "▀▘▝▘▝▀▘ ▝▀▝▘        ",
688            "▗▛▜▖                ",
689            "█   ▜▟▜▖▟▀▙ ▟▀▙ █▀▙ ",
690            "▜▖▜▌▐▌▝▘█▀▀ █▀▀ █ █ ",
691            " ▀▀▘▀▀  ▝▀▘ ▝▀▘ ▀ ▀ ",
692            "▜▛▜▖▝█              ",
693            "▐▙▟▘ █  █ █ ▟▀▙     ",
694            "▐▌▐▌ █  █ █ █▀▀     ",
695            "▀▀▀ ▝▀▘ ▝▀▝▘▝▀▘     ",
696        ]);
697        expected.set_style(Rect::new(0, 0, 12, 4), Style::new().red());
698        expected.set_style(Rect::new(0, 4, 20, 4), Style::new().green());
699        expected.set_style(Rect::new(0, 8, 16, 4), Style::new().blue());
700        assert_eq!(buf, expected);
701    }
702
703    #[test]
704    fn render_third_height_single_line() {
705        let big_text = BigText::builder()
706            .pixel_size(PixelSize::ThirdHeight)
707            .lines(vec![Line::from("SingleLine")])
708            .build();
709        let mut buf = Buffer::empty(Rect::new(0, 0, 80, 3));
710        big_text.render(buf.area, &mut buf);
711        let expected = Buffer::with_lines(vec![
712            "🬹█🬰🬂🬎🬋   🬭🬰🬰    🬭🬭🬭🬭🬭    🬭🬭🬭 🬭🬭  🬂██     🬭🬭🬭🬭   🬂██🬂     🬭🬰🬰    🬭🬭🬭🬭🬭    🬭🬭🬭🬭   ",
713            "🬭🬰🬂🬎🬹🬹    ██    ██  ██  🬎█🬭🬭██    ██    ██🬋🬋🬎🬎   ██  🬭🬹   ██    ██  ██  ██🬋🬋🬎🬎  ",
714            " 🬂🬂🬂🬂    🬂🬂🬂🬂   🬂🬂  🬂🬂  🬋🬋🬋🬋🬎🬂   🬂🬂🬂🬂    🬂🬂🬂🬂   🬂🬂🬂🬂🬂🬂🬂  🬂🬂🬂🬂   🬂🬂  🬂🬂   🬂🬂🬂🬂   ",
715        ]);
716        assert_eq!(buf, expected);
717    }
718
719    #[test]
720    fn render_third_height_truncated() {
721        let big_text = BigText::builder()
722            .pixel_size(PixelSize::ThirdHeight)
723            .lines(vec![Line::from("Truncated")])
724            .build();
725        let mut buf = Buffer::empty(Rect::new(0, 0, 70, 2));
726        big_text.render(buf.area, &mut buf);
727        let expected = Buffer::with_lines(vec![
728            "🬎🬂██🬂🬎  🬭🬭 🬭🬭🬭  🬭🬭  🬭🬭  🬭🬭🬭🬭🬭    🬭🬭🬭🬭    🬭🬭🬭🬭    🬭🬹█🬭🬭   🬭🬭🬭🬭      🬂██",
729            "  ██     ██🬂 🬎🬎 ██  ██  ██  ██  ██  🬰🬰  🬭🬹🬋🬋██    ██ 🬭  ██🬋🬋🬎🬎  🬹█🬂🬂██",
730        ]);
731        assert_eq!(buf, expected);
732    }
733
734    #[test]
735    fn render_third_height_multiple_lines() {
736        let big_text = BigText::builder()
737            .pixel_size(PixelSize::ThirdHeight)
738            .lines(vec![Line::from("Multi"), Line::from("Lines")])
739            .build();
740        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 6));
741        big_text.render(buf.area, &mut buf);
742        let expected = Buffer::with_lines(vec![
743            "██🬹🬭🬹██ 🬭🬭  🬭🬭   🬂██     🬭🬹█🬭🬭   🬭🬰🬰    ",
744            "██🬂🬎🬂██ ██  ██    ██      ██ 🬭    ██    ",
745            "🬂🬂   🬂🬂  🬂🬂🬂 🬂🬂  🬂🬂🬂🬂      🬂🬂    🬂🬂🬂🬂   ",
746            "🬂██🬂     🬭🬰🬰    🬭🬭🬭🬭🬭    🬭🬭🬭🬭    🬭🬭🬭🬭🬭  ",
747            " ██  🬭🬹   ██    ██  ██  ██🬋🬋🬎🬎  🬂🬎🬋🬋🬹🬭  ",
748            "🬂🬂🬂🬂🬂🬂🬂  🬂🬂🬂🬂   🬂🬂  🬂🬂   🬂🬂🬂🬂   🬂🬂🬂🬂🬂   ",
749        ]);
750        assert_eq!(buf, expected);
751    }
752
753    #[test]
754    fn render_third_height_widget_style() {
755        let big_text = BigText::builder()
756            .pixel_size(PixelSize::ThirdHeight)
757            .lines(vec![Line::from("Styled")])
758            .style(Style::new().bold())
759            .build();
760        let mut buf = Buffer::empty(Rect::new(0, 0, 48, 3));
761        big_text.render(buf.area, &mut buf);
762        let mut expected = Buffer::with_lines(vec![
763            "🬹█🬰🬂🬎🬋   🬭🬹█🬭🬭  🬭🬭  🬭🬭   🬂██     🬭🬭🬭🬭      🬂██  ",
764            "🬭🬰🬂🬎🬹🬹    ██ 🬭  🬎█🬭🬭██    ██    ██🬋🬋🬎🬎  🬹█🬂🬂██  ",
765            " 🬂🬂🬂🬂      🬂🬂   🬋🬋🬋🬋🬎🬂   🬂🬂🬂🬂    🬂🬂🬂🬂    🬂🬂🬂 🬂🬂 ",
766        ]);
767        expected.set_style(Rect::new(0, 0, 48, 3), Style::new().bold());
768        assert_eq!(buf, expected);
769    }
770
771    #[test]
772    fn render_third_height_line_style() {
773        let big_text = BigText::builder()
774            .pixel_size(PixelSize::ThirdHeight)
775            .lines(vec![
776                Line::from("Red".red()),
777                Line::from("Green".green()),
778                Line::from("Blue".blue()),
779            ])
780            .build();
781        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 9));
782        big_text.render(buf.area, &mut buf);
783        let mut expected = Buffer::with_lines(vec![
784            "🬂██🬂🬂█🬹  🬭🬭🬭🬭      🬂██                  ",
785            " ██🬂🬎█🬭 ██🬋🬋🬎🬎  🬹█🬂🬂██                  ",
786            "🬂🬂🬂  🬂🬂  🬂🬂🬂🬂    🬂🬂🬂 🬂🬂                 ",
787            "🬭🬹🬎🬂🬂🬎🬋 🬭🬭 🬭🬭🬭   🬭🬭🬭🬭    🬭🬭🬭🬭   🬭🬭🬭🬭🬭   ",
788            "🬎█🬭 🬋🬹🬹  ██🬂 🬎🬎 ██🬋🬋🬎🬎  ██🬋🬋🬎🬎  ██  ██  ",
789            "  🬂🬂🬂🬂🬂 🬂🬂🬂🬂     🬂🬂🬂🬂    🬂🬂🬂🬂   🬂🬂  🬂🬂  ",
790            "🬂██🬂🬂█🬹  🬂██    🬭🬭  🬭🬭   🬭🬭🬭🬭           ",
791            " ██🬂🬂█🬹   ██    ██  ██  ██🬋🬋🬎🬎          ",
792            "🬂🬂🬂🬂🬂🬂   🬂🬂🬂🬂    🬂🬂🬂 🬂🬂  🬂🬂🬂🬂           ",
793        ]);
794        expected.set_style(Rect::new(0, 0, 24, 3), Style::new().red());
795        expected.set_style(Rect::new(0, 3, 40, 3), Style::new().green());
796        expected.set_style(Rect::new(0, 6, 32, 3), Style::new().blue());
797        assert_eq!(buf, expected);
798    }
799
800    #[test]
801    fn render_sextant_size_single_line() {
802        let big_text = BigText::builder()
803            .pixel_size(PixelSize::Sextant)
804            .lines(vec![Line::from("SingleLine")])
805            .build();
806        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 3));
807        big_text.render(buf.area, &mut buf);
808        let expected = Buffer::with_lines(vec![
809            "🬻🬒🬌 🬞🬰  🬭🬭🬏 🬞🬭🬞🬏🬁█  🬞🬭🬏 🬨🬕  🬞🬰  🬭🬭🬏 🬞🬭🬏 ",
810            "🬯🬊🬹  █  █ █ 🬬🬭█  █  █🬋🬎 ▐▌🬞🬓 █  █ █ █🬋🬎 ",
811            "🬁🬂🬀 🬁🬂🬀 🬂 🬂 🬋🬋🬆 🬁🬂🬀 🬁🬂🬀 🬂🬂🬂🬀🬁🬂🬀 🬂 🬂 🬁🬂🬀 ",
812        ]);
813        assert_eq!(buf, expected);
814    }
815
816    #[test]
817    fn render_sextant_size_truncated() {
818        let big_text = BigText::builder()
819            .pixel_size(PixelSize::Sextant)
820            .lines(vec![Line::from("Truncated")])
821            .build();
822        let mut buf = Buffer::empty(Rect::new(0, 0, 35, 2));
823        big_text.render(buf.area, &mut buf);
824        let expected = Buffer::with_lines(vec![
825            "🬆█🬊 🬭🬞🬭 🬭 🬭 🬭🬭🬏 🬞🬭🬏 🬞🬭🬏 🬞🬻🬭 🬞🬭🬏  🬁█",
826            " █  ▐🬕🬉🬄█ █ █ █ █ 🬰 🬵🬋█  █🬞 █🬋🬎 🬻🬂█",
827        ]);
828        assert_eq!(buf, expected);
829    }
830
831    #[test]
832    fn render_sextant_size_multiple_lines() {
833        let big_text = BigText::builder()
834            .pixel_size(PixelSize::Sextant)
835            .lines(vec![Line::from("Multi"), Line::from("Lines")])
836            .build();
837        let mut buf = Buffer::empty(Rect::new(0, 0, 20, 6));
838        big_text.render(buf.area, &mut buf);
839        let expected = Buffer::with_lines(vec![
840            "█🬱🬻▌🬭 🬭 🬁█  🬞🬻🬭 🬞🬰  ",
841            "█🬊🬨▌█ █  █   █🬞  █  ",
842            "🬂 🬁🬀🬁🬂🬁🬀🬁🬂🬀  🬁🬀 🬁🬂🬀 ",
843            "🬨🬕  🬞🬰  🬭🬭🬏 🬞🬭🬏 🬞🬭🬭 ",
844            "▐▌🬞🬓 █  █ █ █🬋🬎 🬊🬋🬱 ",
845            "🬂🬂🬂🬀🬁🬂🬀 🬂 🬂 🬁🬂🬀 🬂🬂🬀 ",
846        ]);
847        assert_eq!(buf, expected);
848    }
849
850    #[test]
851    fn render_sextant_size_widget_style() {
852        let big_text = BigText::builder()
853            .pixel_size(PixelSize::Sextant)
854            .lines(vec![Line::from("Styled")])
855            .style(Style::new().bold())
856            .build();
857        let mut buf = Buffer::empty(Rect::new(0, 0, 24, 3));
858        big_text.render(buf.area, &mut buf);
859        let mut expected = Buffer::with_lines(vec![
860            "🬻🬒🬌 🬞🬻🬭 🬭 🬭 🬁█  🬞🬭🬏  🬁█ ",
861            "🬯🬊🬹  █🬞 🬬🬭█  █  █🬋🬎 🬻🬂█ ",
862            "🬁🬂🬀  🬁🬀 🬋🬋🬆 🬁🬂🬀 🬁🬂🬀 🬁🬂🬁🬀",
863        ]);
864        expected.set_style(Rect::new(0, 0, 24, 3), Style::new().bold());
865        assert_eq!(buf, expected);
866    }
867
868    #[test]
869    fn render_sextant_size_line_style() {
870        let big_text = BigText::builder()
871            .pixel_size(PixelSize::Sextant)
872            .lines(vec![
873                Line::from("Red".red()),
874                Line::from("Green".green()),
875                Line::from("Blue".blue()),
876            ])
877            .build();
878        let mut buf = Buffer::empty(Rect::new(0, 0, 20, 9));
879        big_text.render(buf.area, &mut buf);
880        let mut expected = Buffer::with_lines(vec![
881            "🬨🬕🬨🬓🬞🬭🬏  🬁█         ",
882            "▐🬕🬬🬏█🬋🬎 🬻🬂█         ",
883            "🬂🬀🬁🬀🬁🬂🬀 🬁🬂🬁🬀        ",
884            "🬵🬆🬊🬃🬭🬞🬭 🬞🬭🬏 🬞🬭🬏 🬭🬭🬏 ",
885            "🬬🬏🬩🬓▐🬕🬉🬄█🬋🬎 █🬋🬎 █ █ ",
886            " 🬂🬂🬀🬂🬂  🬁🬂🬀 🬁🬂🬀 🬂 🬂 ",
887            "🬨🬕🬨🬓🬁█  🬭 🬭 🬞🬭🬏     ",
888            "▐🬕🬨🬓 █  █ █ █🬋🬎     ",
889            "🬂🬂🬂 🬁🬂🬀 🬁🬂🬁🬀🬁🬂🬀     ",
890        ]);
891        expected.set_style(Rect::new(0, 0, 12, 3), Style::new().red());
892        expected.set_style(Rect::new(0, 3, 20, 3), Style::new().green());
893        expected.set_style(Rect::new(0, 6, 16, 3), Style::new().blue());
894        assert_eq!(buf, expected);
895    }
896
897    #[test]
898    fn render_quarter_height_single_line() {
899        let big_text = BigText::builder()
900            .pixel_size(PixelSize::QuarterHeight)
901            .lines(vec![Line::from("SingleLine")])
902            .build();
903        let mut buf = Buffer::empty(Rect::new(0, 0, 80, 2));
904        big_text.render(buf.area, &mut buf);
905        let expected = Buffer::with_lines(vec![
906            "𜴳█𜷝𜶮▀𜴆   𜴧𜷝𜷝    ▄▄𜴧𜴧▄▂  ▂▄𜴧𜴧▂▄𜴧  🮂██    ▂▄𜴧𜴧▄▂  🮂██🮂     𜴧𜷝𜷝    ▄▄𜴧𜴧▄▂  ▂▄𜴧𜴧▄▂  ",
907            "𜴆𜴳𜴧𜴪🮅▀   𜴧🮅🮅𜴧   🮅🮅  🮅🮅  𜶮𜶺𜶷𜶷█🮅   𜴧🮅🮅𜴧   ▀🮅𜴪𜴪𜴪🮂  𜴧🮅🮅𜴧𜴧𜴳🮅  𜴧🮅🮅𜴧   🮅🮅  🮅🮅  ▀🮅𜴪𜴪𜴪🮂  ",
908        ]);
909        assert_eq!(buf, expected);
910    }
911
912    #[test]
913    fn render_quarter_height_truncated() {
914        let big_text = BigText::builder()
915            .pixel_size(PixelSize::QuarterHeight)
916            .lines(vec![Line::from("Truncated")])
917            .build();
918        let mut buf = Buffer::empty(Rect::new(0, 0, 70, 1));
919        big_text.render(buf.area, &mut buf);
920        let expected = Buffer::with_lines(vec![
921            "▀🮂██🮂▀  𜴧▄▂▄𜴧▄▂ ▄▄  ▄▄  ▄▄𜴧𜴧▄▂  ▂▄𜴧𜴧▄▂   𜴧𜴧𜴧▄▂   𜴧▆█𜴧𜴧  ▂▄𜴧𜴧▄▂   ▂▂𜶮██",
922        ]);
923        assert_eq!(buf, expected);
924    }
925
926    #[test]
927    fn render_quarter_height_multiple_lines() {
928        let big_text = BigText::builder()
929            .pixel_size(PixelSize::QuarterHeight)
930            .lines(vec![Line::from("Multi"), Line::from("Lines")])
931            .build();
932        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 4));
933        big_text.render(buf.area, &mut buf);
934        let expected = Buffer::with_lines(vec![
935            "██▆▄▆██ ▄▄  ▄▄   🮂██     𜴧▆█𜴧𜴧   𜴧𜷝𜷝    ",
936            "🮅🮅 🮂 🮅🮅 ▀🮅𜴧𜴧▀🮅𜴧  𜴧🮅🮅𜴧     ▀🮅𜴧𜴆   𜴧🮅🮅𜴧   ",
937            "🮂██🮂     𜴧𜷝𜷝    ▄▄𜴧𜴧▄▂  ▂▄𜴧𜴧▄▂  ▂▄𜴧𜴧𜴧𜴧  ",
938            "𜴧🮅🮅𜴧𜴧𜴳🮅  𜴧🮅🮅𜴧   🮅🮅  🮅🮅  ▀🮅𜴪𜴪𜴪🮂  𜴧𜴪𜴪𜴪🮅𜴆  ",
939        ]);
940        assert_eq!(buf, expected);
941    }
942
943    #[test]
944    fn render_quarter_height_widget_style() {
945        let big_text = BigText::builder()
946            .pixel_size(PixelSize::QuarterHeight)
947            .lines(vec![Line::from("Styled")])
948            .style(Style::new().bold())
949            .build();
950        let mut buf = Buffer::empty(Rect::new(0, 0, 48, 2));
951        big_text.render(buf.area, &mut buf);
952        let mut expected = Buffer::with_lines(vec![
953            "𜴳█𜷝𜶮▀𜴆   𜴧▆█𜴧𜴧  ▄▄  ▄▄   🮂██    ▂▄𜴧𜴧▄▂   ▂▂𜶮██  ",
954            "𜴆𜴳𜴧𜴪🮅▀    ▀🮅𜴧𜴆  𜶮𜶺𜶷𜶷█🮅   𜴧🮅🮅𜴧   ▀🮅𜴪𜴪𜴪🮂  ▀🮅𜴧𜴧▀🮅𜴧 ",
955        ]);
956        expected.set_style(Rect::new(0, 0, 48, 2), Style::new().bold());
957        assert_eq!(buf, expected);
958    }
959
960    #[test]
961    fn render_quarter_height_line_style() {
962        let big_text = BigText::builder()
963            .pixel_size(PixelSize::QuarterHeight)
964            .lines(vec![
965                Line::from("Red".red()),
966                Line::from("Green".green()),
967                Line::from("Blue".blue()),
968            ])
969            .build();
970        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 6));
971        big_text.render(buf.area, &mut buf);
972        let mut expected = Buffer::with_lines(vec![
973            "🮂██𜶮𜶮█𜴳 ▂▄𜴧𜴧▄▂   ▂▂𜶮██                  ",
974            "𜴧🮅🮅 🮂🮅𜴳 ▀🮅𜴪𜴪𜴪🮂  ▀🮅𜴧𜴧▀🮅𜴧                 ",
975            "▄▆▀🮂🮂▀𜴆 𜴧▄▂▄𜴧▄▂ ▂▄𜴧𜴧▄▂  ▂▄𜴧𜴧▄▂  ▄▄𜴧𜴧▄▂  ",
976            "🮂▀𜴳𜴧𜴪🮅🮅 𜴧🮅🮅𜴧 🮂🮂 ▀🮅𜴪𜴪𜴪🮂  ▀🮅𜴪𜴪𜴪🮂  🮅🮅  🮅🮅  ",
977            "🮂██𜶮𜶮█𜴳  🮂██    ▄▄  ▄▄  ▂▄𜴧𜴧▄▂          ",
978            "𜴧🮅🮅𜴧𜴧🮅▀  𜴧🮅🮅𜴧   ▀🮅𜴧𜴧▀🮅𜴧 ▀🮅𜴪𜴪𜴪🮂          ",
979        ]);
980        expected.set_style(Rect::new(0, 0, 24, 2), Style::new().red());
981        expected.set_style(Rect::new(0, 2, 40, 2), Style::new().green());
982        expected.set_style(Rect::new(0, 4, 32, 2), Style::new().blue());
983        assert_eq!(buf, expected);
984    }
985
986    #[test]
987    fn render_octant_size_single_line() {
988        let big_text = BigText::builder()
989            .pixel_size(PixelSize::Octant)
990            .lines(vec![Line::from("SingleLine")])
991            .build();
992        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 2));
993        big_text.render(buf.area, &mut buf);
994        let expected = Buffer::with_lines(vec![
995            "𜶪𜶾𜴇 𜴘𜷝  ▄𜴧𜶻 𜷋𜴧𜷋𜴉𜺫█  𜷋𜴧𜶻 𜶘𜵊  𜴘𜷝  ▄𜴧𜶻 𜷋𜴧𜶻 ",
996            "𜴣𜴩𜴗 𜴘🮅𜴉 🮅 🮅 𜶶𜶷𜵰 𜴘🮅𜴉 𜴦𜴪𜴌 𜴱𜴬𜴯𜴍𜴘🮅𜴉 🮅 🮅 𜴦𜴪𜴌 ",
997        ]);
998        assert_eq!(buf, expected);
999    }
1000
1001    #[test]
1002    #[rustfmt::skip]
1003    fn render_octant_size_truncated() {
1004        let big_text = BigText::builder()
1005            .pixel_size(PixelSize::Octant)
1006            .lines(vec![Line::from("Truncated")])
1007            .build();
1008        let mut buf = Buffer::empty(Rect::new(0, 0, 35, 1));
1009        big_text.render(buf.area, &mut buf);
1010        let expected = Buffer::with_lines(vec![
1011            "𜴂█𜴅 𜶜𜷋𜶜𜺣▄ ▄ ▄𜴧𜶻 𜷋𜴧𜶻 𜴘𜴧𜶻 𜴘𜷥𜴧 𜷋𜴧𜶻 𜺠𜶭█",
1012        ]);
1013        assert_eq!(buf, expected);
1014    }
1015
1016    #[test]
1017    fn render_octant_size_multiple_lines() {
1018        let big_text = BigText::builder()
1019            .pixel_size(PixelSize::Octant)
1020            .lines(vec![Line::from("Multi"), Line::from("Lines")])
1021            .build();
1022        let mut buf = Buffer::empty(Rect::new(0, 0, 20, 4));
1023        big_text.render(buf.area, &mut buf);
1024        let expected = Buffer::with_lines(vec![
1025            "█𜷞𜷥▌▄ ▄ 𜺫█  𜴘𜷥𜴧 𜴘𜷝  ",
1026            "🮅𜺫𜴡𜴍𜴦𜴧𜴦𜴉𜴘🮅𜴉  𜴦𜴐 𜴘🮅𜴉 ",
1027            "𜶘𜵊  𜴘𜷝  ▄𜴧𜶻 𜷋𜴧𜶻 𜷋𜴧𜴧 ",
1028            "𜴱𜴬𜴯𜴍𜴘🮅𜴉 🮅 🮅 𜴦𜴪𜴌 𜴩𜴪𜴕 ",
1029        ]);
1030        assert_eq!(buf, expected);
1031    }
1032
1033    #[test]
1034    #[rustfmt::skip]
1035    fn render_octant_size_widget_style() {
1036        let big_text = BigText::builder()
1037            .pixel_size(PixelSize::Octant)
1038            .lines(vec![Line::from("Styled")])
1039            .style(Style::new().bold())
1040            .build();
1041        let mut buf = Buffer::empty(Rect::new(0, 0, 24, 2));
1042        big_text.render(buf.area, &mut buf);
1043        let mut expected = Buffer::with_lines(vec![
1044            "𜶪𜶾𜴇 𜴘𜷥𜴧 ▄ ▄ 𜺫█  𜷋𜴧𜶻 𜺠𜶭█ ",
1045            "𜴣𜴩𜴗  𜴦𜴐 𜶶𜶷𜵰 𜴘🮅𜴉 𜴦𜴪𜴌 𜴦𜴧𜴦𜴉",
1046        ]);
1047        expected.set_style(Rect::new(0, 0, 24, 2), Style::new().bold());
1048        assert_eq!(buf, expected);
1049    }
1050
1051    #[test]
1052    fn render_octant_size_line_style() {
1053        let big_text = BigText::builder()
1054            .pixel_size(PixelSize::Octant)
1055            .lines(vec![
1056                Line::from("Red".red()),
1057                Line::from("Green".green()),
1058                Line::from("Blue".blue()),
1059            ])
1060            .build();
1061        let mut buf = Buffer::empty(Rect::new(0, 0, 20, 6));
1062        big_text.render(buf.area, &mut buf);
1063        let mut expected = Buffer::with_lines(vec![
1064            "𜶘𜷂𜷖🯦𜷋𜴧𜶻 𜺠𜶭█         ",
1065            "𜴱𜴍𜴢🯦𜴦𜴪𜴌 𜴦𜴧𜴦𜴉        ",
1066            "𜷡𜴂𜴅𜴀𜶜𜷋𜶜𜺣𜷋𜴧𜶻 𜷋𜴧𜶻 ▄𜴧𜶻 ",
1067            "𜴅𜴫𜴲𜴍𜴱𜴬𜺫𜺨𜴦𜴪𜴌 𜴦𜴪𜴌 🮅 🮅 ",
1068            "𜶘𜷂𜷖🯦𜺫█  ▄ ▄ 𜷋𜴧𜶻     ",
1069            "𜴱𜴬𜴱▘𜴘🮅𜴉 𜴦𜴧𜴦𜴉𜴦𜴪𜴌     ",
1070        ]);
1071        expected.set_style(Rect::new(0, 0, 12, 2), Style::new().red());
1072        expected.set_style(Rect::new(0, 2, 20, 2), Style::new().green());
1073        expected.set_style(Rect::new(0, 4, 16, 2), Style::new().blue());
1074        assert_eq!(buf, expected);
1075    }
1076
1077    #[test]
1078    fn render_alignment_left() {
1079        let big_text = BigText::builder()
1080            .pixel_size(PixelSize::Quadrant)
1081            .lines(vec![Line::from("Left")])
1082            .alignment(Alignment::Left)
1083            .build();
1084        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 4));
1085        big_text.render(buf.area, &mut buf);
1086        let expected = Buffer::with_lines(vec![
1087            "▜▛      ▗▛▙  ▟                          ",
1088            "▐▌  ▟▀▙ ▟▙  ▝█▀                         ",
1089            "▐▌▗▌█▀▀ ▐▌   █▗                         ",
1090            "▀▀▀▘▝▀▘ ▀▀   ▝▘                         ",
1091        ]);
1092        assert_eq!(buf, expected);
1093    }
1094
1095    #[test]
1096    fn render_alignment_right() {
1097        let big_text = BigText::builder()
1098            .pixel_size(PixelSize::Quadrant)
1099            .lines(vec![Line::from("Right")])
1100            .alignment(Alignment::Right)
1101            .build();
1102        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 4));
1103        big_text.render(buf.area, &mut buf);
1104        let expected = Buffer::with_lines(vec![
1105            "                    ▜▛▜▖ ▀      ▜▌   ▟  ",
1106            "                    ▐▙▟▘▝█  ▟▀▟▘▐▙▜▖▝█▀ ",
1107            "                    ▐▌▜▖ █  ▜▄█ ▐▌▐▌ █▗ ",
1108            "                    ▀▘▝▘▝▀▘ ▄▄▛ ▀▘▝▘ ▝▘ ",
1109        ]);
1110        assert_eq!(buf, expected);
1111    }
1112
1113    #[test]
1114    fn render_alignment_center() {
1115        let big_text = BigText::builder()
1116            .pixel_size(PixelSize::Quadrant)
1117            .lines(vec![Line::from("Centered"), Line::from("Lines")])
1118            .alignment(Alignment::Center)
1119            .build();
1120        let mut buf = Buffer::empty(Rect::new(0, 0, 40, 8));
1121        big_text.render(buf.area, &mut buf);
1122        let expected = Buffer::with_lines(vec![
1123            "    ▗▛▜▖         ▟               ▝█     ",
1124            "    █   ▟▀▙ █▀▙ ▝█▀ ▟▀▙ ▜▟▜▖▟▀▙ ▗▄█     ",
1125            "    ▜▖▗▖█▀▀ █ █  █▗ █▀▀ ▐▌▝▘█▀▀ █ █     ",
1126            "     ▀▀ ▝▀▘ ▀ ▀  ▝▘ ▝▀▘ ▀▀  ▝▀▘ ▝▀▝▘    ",
1127            "          ▜▛   ▀                        ",
1128            "          ▐▌  ▝█  █▀▙ ▟▀▙ ▟▀▀           ",
1129            "          ▐▌▗▌ █  █ █ █▀▀ ▝▀▙           ",
1130            "          ▀▀▀▘▝▀▘ ▀ ▀ ▝▀▘ ▀▀▘           ",
1131        ]);
1132        assert_eq!(buf, expected);
1133    }
1134}