fix: left-align thumbnails and tuck text beside the image

This commit is contained in:
2026-10-11 11:48:29 +02:00
parent 4205b56653
commit 755c87f918
2 changed files with 28 additions and 17 deletions
+22 -14
View File
@@ -96,23 +96,25 @@ impl Thumbnail {
.is_some_and(|image| image.complete && image.protocol.protocol_type().is_some())
}
pub fn draw(&mut self, frame: &mut Frame, area: Rect) {
/// Draw the image left-aligned and return its occupied width for adjacent content.
pub fn draw(&mut self, frame: &mut Frame, mut area: Rect) -> u16 {
self.poll();
if area.width == 0 || area.height == 0 || self.selected.is_none() {
return;
return area.width;
}
let mut message = self.error.as_deref().unwrap_or("Loading thumbnail...");
if let Some(image) = self.image.as_mut() {
let resize = Resize::Scale(Some(FilterType::Triangle));
if let Some(size) = image.protocol.size_for(resize.clone(), area.into()) {
area = left_aligned(area, size);
frame.render_stateful_widget(
StatefulImage::new().resize(resize),
right_aligned(area, size),
area,
&mut image.protocol,
);
if image.protocol.protocol_type().is_some() {
return;
return area.width;
}
}
message = "Preparing thumbnail...";
@@ -130,6 +132,7 @@ impl Thumbnail {
area.height - area.height / 2,
),
);
area.width
}
fn poll(&mut self) {
@@ -235,15 +238,10 @@ fn decode(bytes: Vec<u8>) -> Result<image::DynamicImage, String> {
.map_err(|error| format!("Could not decode thumbnail JPEG: {error}"))
}
fn right_aligned(area: Rect, size: Size) -> Rect {
fn left_aligned(area: Rect, size: Size) -> Rect {
let width = size.width.min(area.width);
let height = size.height.min(area.height);
Rect::new(
area.x + area.width - width,
area.y + (area.height - height) / 2,
width,
height,
)
Rect::new(area.x, area.y + (area.height - height) / 2, width, height)
}
#[cfg(test)]
@@ -309,7 +307,11 @@ mod tests {
});
let mut terminal = Terminal::new(TestBackend::new(100, 40)).unwrap();
for area in [Rect::new(3, 2, 80, 18), Rect::new(7, 4, 30, 8)] {
terminal.draw(|frame| thumbnail.draw(frame, area)).unwrap();
terminal
.draw(|frame| {
thumbnail.draw(frame, area);
})
.unwrap();
assert!(thumbnail.is_loading());
let response = requests_rx
.recv_timeout(Duration::from_secs(2))
@@ -317,7 +319,12 @@ mod tests {
.resize_encode()
.unwrap();
replies_tx.send(Ok(response)).unwrap();
terminal.draw(|frame| thumbnail.draw(frame, area)).unwrap();
let mut occupied_width = 0;
terminal
.draw(|frame| {
occupied_width = thumbnail.draw(frame, area);
})
.unwrap();
assert!(!thumbnail.is_loading());
let buffer = terminal.backend().buffer();
let pixels: Vec<_> = (0..40)
@@ -332,7 +339,8 @@ mod tests {
let top = pixels.iter().map(|&(_, y)| y).min().unwrap();
let bottom = pixels.iter().map(|&(_, y)| y).max().unwrap() + 1;
assert!(left >= area.x && right <= area.right());
assert_eq!(right, area.right()); // Keep the image against the metadata-facing edge.
assert_eq!(left, area.x);
assert_eq!(occupied_width, right - left);
assert!(top >= area.y && bottom <= area.bottom());
assert!(right - left == area.width || bottom - top == area.height);
assert!((top - area.y).abs_diff(area.bottom() - bottom) <= 1);