broot/image/
double_line.rs

1use {
2    super::zune_compat::Rgba,
3    crate::{
4        display::W,
5        errors::ProgramError,
6    },
7    ansi_colours,
8    crokey::crossterm::{
9        QueueableCommand,
10        style::{
11            Color,
12            Colors,
13            Print,
14            SetColors,
15        },
16    },
17    termimad::fill_bg,
18};
19
20const UPPER_HALF_BLOCK: char = '▀';
21
22/// A "double line" normally contains two lines of pixels
23/// which are displayed as one line of characters, the
24/// UPPER_HALF_BLOCK foreground for the upper pixel and
25/// the background of the char for the lower pixel.
26/// It acts as a buffer which is dumped to screen when
27/// full or when the image is totally read.
28pub struct DoubleLine {
29    img_width: usize,
30    pixels: Vec<Color>, // size twice img_width
31    true_colors: bool,
32}
33
34impl DoubleLine {
35    pub fn new(
36        img_width: usize,
37        true_colors: bool,
38    ) -> Self {
39        Self {
40            img_width,
41            pixels: Vec::with_capacity(2 * img_width),
42            true_colors,
43        }
44    }
45    pub fn push(
46        &mut self,
47        rgba: Rgba<u8>,
48    ) {
49        self.pixels.push(if self.true_colors {
50            Color::Rgb {
51                r: rgba[0],
52                g: rgba[1],
53                b: rgba[2],
54            }
55        } else {
56            Color::AnsiValue(ansi_colours::ansi256_from_rgb((rgba[0], rgba[1], rgba[2])))
57        });
58    }
59    pub fn is_empty(&self) -> bool {
60        self.pixels.is_empty()
61    }
62    pub fn is_full(&self) -> bool {
63        self.pixels.len() == 2 * self.img_width
64    }
65    pub fn write(
66        &mut self,
67        w: &mut W,
68        left_margin: usize,
69        right_margin: usize,
70        bg: Color,
71    ) -> Result<(), ProgramError> {
72        debug_assert!(
73            self.pixels.len() == self.img_width || self.pixels.len() == 2 * self.img_width
74        );
75        // we may have either one or two lines
76        let simple = self.pixels.len() < 2 * self.img_width;
77        fill_bg(w, left_margin, bg)?;
78        for i in 0..self.img_width {
79            let foreground_color = self.pixels[i];
80            let background_color = if simple {
81                bg
82            } else {
83                self.pixels[i + self.img_width]
84            };
85            w.queue(SetColors(Colors::new(foreground_color, background_color)))?;
86            w.queue(Print(UPPER_HALF_BLOCK))?;
87        }
88        fill_bg(w, right_margin, bg)?;
89        self.pixels.clear();
90        Ok(())
91    }
92}