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