Skip to main content

tui_big_text/
big_text.rs

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