Skip to main content

cursive_image/
view.rs

1use super::{image::*, image_view::*, kitty::*, sizing::*, state::*, vec2f::*};
2
3use cursive::*;
4
5const TYPE_NAME: &str = "ImageView";
6
7impl View for ImageView {
8    fn type_name(&self) -> &'static str {
9        TYPE_NAME
10    }
11
12    fn required_size(&mut self, constraint: Vec2) -> Vec2 {
13        match &self.image {
14            Some(image) => {
15                let size = self.image_size_in_cells(image);
16                match self.sizing {
17                    Sizing::Shrink => {
18                        let constraint = constraint.into_vec2f();
19                        if size > constraint { size.scale_to_fit(constraint) } else { size }
20                    }
21
22                    Sizing::Fit => size.scale_to_fit(constraint.into_vec2f()),
23
24                    Sizing::Scale(scale) => size.scale(scale),
25                }
26                .into_vec2()
27            }
28
29            None => (1, 1).into(),
30        }
31    }
32
33    fn needs_relayout(&self) -> bool {
34        false
35    }
36
37    fn layout(&mut self, size: Vec2) {
38        if self.size != Some(size) {
39            self.size = Some(size);
40            self.set_content_offset(None);
41            self.set_state(State::Ready);
42        }
43    }
44
45    fn draw(&self, printer: &Printer) {
46        let Some(image) = &self.image else {
47            return;
48        };
49
50        if self.get_content_offset() != Some(printer.content_offset) {
51            self.set_content_offset(Some(printer.content_offset));
52
53            // Force draw
54            self.set_state(State::Ready);
55        }
56
57        if self.get_state().is_ready() {
58            let mut window = None;
59
60            let constraint = printer.output_size.into_vec2f();
61            let size = match self.sizing {
62                Sizing::Shrink => {
63                    let size = self.image_size_in_cells(image);
64                    if size > constraint { size.scale_to_fit(constraint) } else { size }
65                }
66
67                Sizing::Fit => self.scale_to_fit_image_size_in_cells(image, constraint),
68
69                Sizing::Scale(scale) => {
70                    let mut size = self.image_size_in_cells(image).scale(scale);
71
72                    let too_wide = size.x > constraint.x;
73                    let too_high = size.y > constraint.y;
74
75                    if too_wide || too_high {
76                        if too_wide {
77                            size.x = constraint.x;
78                        }
79
80                        if too_high {
81                            size.y = constraint.y;
82                        }
83
84                        // Window is in pixels
85                        window = Some(Rect::from_size(
86                            self.into_pixels(printer.content_offset.into_vec2f()),
87                            self.into_pixels(size),
88                        ));
89                    }
90
91                    size
92                }
93            };
94
95            let size = size.into_vec2();
96            let position: Vec2 = (
97                (printer.offset.x + self.align.h.get_offset(size.x, printer.output_size.x)),
98                (printer.offset.y + self.align.v.get_offset(size.y, printer.output_size.y)),
99            )
100                .into();
101
102            _ = image.display(position, Some(size), window);
103
104            self.set_state(State::Visible);
105        }
106    }
107}
108
109impl ImageView {
110    fn into_pixels(&self, vec: Vec2f) -> Vec2 {
111        vec.scale_vec(self.cell_size).into_vec2()
112    }
113
114    fn image_size_in_cells(&self, image: &Image) -> Vec2f {
115        image.size.into_vec2f().reverse_scale_vec(self.cell_size)
116    }
117
118    fn scale_to_fit_image_size_in_cells(&self, image: &Image, constraint: Vec2f) -> Vec2f {
119        // Note that the image size is in pixels
120        // Because we are already scaling it to cells there is no need to convert it to cells
121        // However, we do need to convert it to the cell aspect ratio
122        let size: Vec2f = (image.size.x as f64 * self.cell_aspect_ratio, image.size.y as f64).into();
123        size.scale_to_fit(constraint)
124    }
125}
126
127// Utils
128
129// fn image_size_in_pixels(image: &DynamicImage) -> Vec2f {
130//     (image.width() as f64, image.height() as f64).into()
131// }