1use super::{image::*, sizing::*, state::*, vec2f::*};
2
3use {
4 cursive::*,
5 image::*,
6 std::io::{self, Write},
7 viuer::*,
8};
9
10const TYPE_NAME: &str = "ImageView";
11
12impl ImageView {
13 fn config(&self, printer: &Printer, image: &DynamicImage) -> (Config, Option<Rect>) {
14 let mut config = Config::default();
15
16 let mut crop = None;
17
18 let constraint = printer.output_size.into_vec2f();
19 let size = match self.sizing {
20 Sizing::Fit => self.image_size_in_cells_fit(image, constraint),
21
22 Sizing::Scale(scale) => {
23 let mut size = self.image_size_in_cells(image).scale(scale);
24
25 let too_wide = size.x > constraint.x;
26 let too_high = size.y > constraint.y;
27
28 if too_wide || too_high {
29 if too_wide {
30 size.x = constraint.x;
31 }
32
33 if too_high {
34 size.y = constraint.y;
35 }
36
37 crop = Some(Rect::from_size(
39 self.into_pixels(printer.content_offset.into_vec2f()),
40 self.into_pixels(size),
41 ));
42 }
43
44 size
45 }
46 };
47
48 config.width = Some(size.x.round() as u32);
49 config.height = Some(size.y.round() as u32);
50
51 let size = size.into_vec2();
52 config.x = (printer.offset.x + self.align.h.get_offset(size.x, printer.output_size.x)) as u16;
53 config.y = (printer.offset.y + self.align.v.get_offset(size.y, printer.output_size.y)) as i16;
54
55 (config, crop)
56 }
57
58 fn delete(&self, ready: bool) {
59 let state = self.state.lock().unwrap();
60 let mut state = state.borrow_mut();
61
62 if state.is_visible() {
63 let mut out = io::stdout();
65 _ = write!(out, "\x1b_Ga=d,d=n,i=0\x1b\\");
66 _ = out.flush();
67 }
68
69 *state = if ready { State::Ready } else { State::Hidden };
70 }
71
72 fn into_pixels(&self, vec: Vec2f) -> Vec2 {
73 vec.scale2(self.cell_size).into_vec2()
74 }
75
76 fn image_size_in_cells(&self, image: &DynamicImage) -> Vec2f {
77 image_size_in_pixels(image).scale2r(self.cell_size)
78 }
79
80 fn image_size_in_cells_fit(&self, image: &DynamicImage, constraint: Vec2f) -> Vec2f {
81 let size: Vec2f = (image.width() as f64 * self.cell_aspect_ratio, image.height() as f64).into();
85 size.scale_to_fit(constraint)
86 }
87}
88
89impl View for ImageView {
90 fn type_name(&self) -> &'static str {
91 TYPE_NAME
92 }
93
94 fn required_size(&mut self, constraint: Vec2) -> Vec2 {
95 match &self.image {
96 Some(image) => {
97 let size = self.image_size_in_cells(image);
98 match self.sizing {
99 Sizing::Fit => size.scale_to_fit(constraint.into_vec2f()),
100 Sizing::Scale(scale) => size.scale(scale),
101 }
102 .into_vec2()
103 }
104
105 None => (1, 1).into(),
106 }
107 }
108
109 fn needs_relayout(&self) -> bool {
110 false
111 }
112
113 fn layout(&mut self, size: Vec2) {
114 if self.size != Some(size) {
115 self.delete(true);
116 }
117
118 self.size = Some(size);
119 }
120
121 fn draw(&self, printer: &Printer) {
122 let Some(image) = &self.image else {
123 return;
124 };
125
126 let delete = {
127 let content_offset = self.content_offset.lock().unwrap();
128 let mut content_offset = content_offset.borrow_mut();
129
130 if *content_offset != Some(printer.content_offset) {
131 *content_offset = Some(printer.content_offset);
132 true
133 } else {
134 false
135 }
136 };
137
138 if delete {
139 self.delete(true);
140 }
141
142 let state = self.state.lock().unwrap();
143 let mut state = state.borrow_mut();
144
145 if state.is_ready() {
146 let (config, crop) = self.config(printer, image);
147
148 _ = match crop {
149 Some(crop) => print(
150 &image.crop_imm(crop.left() as u32, crop.top() as u32, crop.width() as u32, crop.height() as u32),
151 &config,
152 ),
153
154 None => print(image, &config),
155 };
156
157 *state = State::Visible;
158 }
159 }
160}
161
162fn image_size_in_pixels(image: &DynamicImage) -> Vec2f {
165 (image.width() as f64, image.height() as f64).into()
166}