1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use std::cmp;

use image::{DynamicImage, Rgb};
use ratatui_image::{picker::Picker, protocol::StatefulProtocol};

use super::{root::ComponentProps, textcomponent::TextNode};

pub struct ImageComponent {
    _alt_text: String,
    y_offset: u16,
    height: u16,
    scroll_offset: u16,
    image: Box<dyn StatefulProtocol>,
}

impl ImageComponent {
    pub fn new<T: ToString>(image: DynamicImage, height: u32, alt_text: T) -> Option<Self> {
        let mut picker = Picker::from_termios().ok()?;
        picker.guess_protocol();
        picker.background_color = Some(Rgb::<u8>([0, 0, 0]));

        let image = picker.new_resize_protocol(image);

        let (_, f_height) = picker.font_size;

        let height = cmp::min(height / f_height as u32, 20) as u16;

        Some(Self {
            height,
            image,
            _alt_text: alt_text.to_string(),
            scroll_offset: 0,
            y_offset: 0,
        })
    }

    pub fn image_mut(&mut self) -> &mut Box<dyn StatefulProtocol> {
        &mut self.image
    }

    pub fn set_scroll_offset(&mut self, offset: u16) {
        self.scroll_offset = offset;
    }

    pub fn scroll_offset(&self) -> u16 {
        self.scroll_offset
    }

    pub fn y_offset(&self) -> u16 {
        self.y_offset
    }

    pub fn height(&self) -> u16 {
        self.height
    }
}

impl ComponentProps for ImageComponent {
    fn height(&self) -> u16 {
        self.height
    }

    fn set_y_offset(&mut self, y_offset: u16) {
        self.y_offset = y_offset;
    }

    fn set_scroll_offset(&mut self, scroll: u16) {
        self.scroll_offset = scroll;
    }

    fn kind(&self) -> TextNode {
        TextNode::Image
    }
}