mirror of
https://github.com/itsjunetime/tdf.git
synced 2026-06-02 08:01:47 -04:00
yaaaay zooming out once you're already zoomed in and respecting kitty's limits for how big of an image to display
This commit is contained in:
+17
-11
@@ -28,14 +28,25 @@ pub enum MaybeTransferred {
|
|||||||
|
|
||||||
pub enum ConvertedImage {
|
pub enum ConvertedImage {
|
||||||
Generic(Protocol),
|
Generic(Protocol),
|
||||||
Kitty { img: MaybeTransferred, area: Rect }
|
Kitty {
|
||||||
|
img: MaybeTransferred,
|
||||||
|
cell_w: u16,
|
||||||
|
cell_h: u16
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConvertedImage {
|
impl ConvertedImage {
|
||||||
pub fn area(&self) -> Rect {
|
pub fn w_h(&self) -> (u16, u16) {
|
||||||
match self {
|
match self {
|
||||||
Self::Generic(prot) => prot.area(),
|
Self::Generic(prot) => {
|
||||||
Self::Kitty { img: _, area } => *area
|
let a = prot.area();
|
||||||
|
(a.width, a.height)
|
||||||
|
}
|
||||||
|
Self::Kitty {
|
||||||
|
img: _,
|
||||||
|
cell_w,
|
||||||
|
cell_h
|
||||||
|
} => (*cell_w, *cell_h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,12 +136,6 @@ pub async fn run_conversion_loop(
|
|||||||
|
|
||||||
let txt_img = match picker.protocol_type() {
|
let txt_img = match picker.protocol_type() {
|
||||||
ProtocolType::Kitty => {
|
ProtocolType::Kitty => {
|
||||||
let area = ratatui_image::protocol::ImageSource::round_pixel_size_to_cells(
|
|
||||||
dyn_img.width(),
|
|
||||||
dyn_img.height(),
|
|
||||||
picker.font_size()
|
|
||||||
);
|
|
||||||
|
|
||||||
let rn = SystemTime::now()
|
let rn = SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
@@ -149,7 +154,8 @@ pub async fn run_conversion_loop(
|
|||||||
img.num_or_id = NumberOrId::Id(NonZeroU32::new(page_num as u32 + 1).unwrap());
|
img.num_or_id = NumberOrId::Id(NonZeroU32::new(page_num as u32 + 1).unwrap());
|
||||||
ConvertedImage::Kitty {
|
ConvertedImage::Kitty {
|
||||||
img: MaybeTransferred::NotYet(img),
|
img: MaybeTransferred::NotYet(img),
|
||||||
area
|
cell_w: page_info.img_data.cell_w,
|
||||||
|
cell_h: page_info.img_data.cell_h
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ConvertedImage::Generic(
|
_ => ConvertedImage::Generic(
|
||||||
|
|||||||
+14
-3
@@ -10,6 +10,8 @@ use crate::{
|
|||||||
FitOrFill, PrerenderLimit, ScaledResult, scale_img_for_area, skip::InterleavedAroundWithMax
|
FitOrFill, PrerenderLimit, ScaledResult, scale_img_for_area, skip::InterleavedAroundWithMax
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const KITTY_MAX_W_OR_H: f32 = 10_000.0;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RenderNotif {
|
pub enum RenderNotif {
|
||||||
Area(Rect),
|
Area(Rect),
|
||||||
@@ -313,6 +315,8 @@ pub fn start_rendering(
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
log::debug!("got pixmap for page {page_num} with WxH {w}x{h}");
|
||||||
|
|
||||||
rendered.num_search_found = Some(ctx.result_rects.len());
|
rendered.num_search_found = Some(ctx.result_rects.len());
|
||||||
rendered.successful = true;
|
rendered.successful = true;
|
||||||
|
|
||||||
@@ -465,11 +469,18 @@ fn render_single_page_to_ctx(
|
|||||||
|
|
||||||
let scaled = scale_img_for_area(page_dim, (area_w, area_h), fit_or_fill);
|
let scaled = scale_img_for_area(page_dim, (area_w, area_h), fit_or_fill);
|
||||||
let ScaledResult {
|
let ScaledResult {
|
||||||
width: surface_w,
|
width: mut surface_w,
|
||||||
height: surface_h,
|
height: mut surface_h,
|
||||||
scale_factor
|
mut scale_factor
|
||||||
} = scaled;
|
} = scaled;
|
||||||
|
|
||||||
|
if surface_w > KITTY_MAX_W_OR_H || surface_h > KITTY_MAX_W_OR_H {
|
||||||
|
let descale = (surface_w / KITTY_MAX_W_OR_H).max(surface_h / KITTY_MAX_W_OR_H);
|
||||||
|
surface_w /= descale;
|
||||||
|
surface_h /= descale;
|
||||||
|
scale_factor /= descale;
|
||||||
|
}
|
||||||
|
|
||||||
let colorspace = Colorspace::device_rgb();
|
let colorspace = Colorspace::device_rgb();
|
||||||
let matrix = Matrix::new_scale(scale_factor, scale_factor);
|
let matrix = Matrix::new_scale(scale_factor, scale_factor);
|
||||||
|
|
||||||
|
|||||||
+51
-20
@@ -79,7 +79,7 @@ struct PageConstraints {
|
|||||||
struct Zoom {
|
struct Zoom {
|
||||||
// just how much 'zoom' you have. Doesn't relate to anything specific yet, except that 0 means
|
// just how much 'zoom' you have. Doesn't relate to anything specific yet, except that 0 means
|
||||||
// it fills the screen (instead of fits)
|
// it fills the screen (instead of fits)
|
||||||
level: u16,
|
level: i16,
|
||||||
// how many terminal-cells worth of content overflow the left side of the screen (and are thus
|
// how many terminal-cells worth of content overflow the left side of the screen (and are thus
|
||||||
// not displayed)
|
// not displayed)
|
||||||
cell_pan_from_left: u16,
|
cell_pan_from_left: u16,
|
||||||
@@ -194,33 +194,46 @@ impl Tui {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|c| matches!(c, ConvertedImage::Kitty { .. }))
|
.is_some_and(|c| matches!(c, ConvertedImage::Kitty { .. }))
|
||||||
{
|
{
|
||||||
let Some(ConvertedImage::Kitty { ref mut img, area }) =
|
let Some(ConvertedImage::Kitty {
|
||||||
self.rendered[self.page].img
|
ref mut img,
|
||||||
|
cell_w,
|
||||||
|
cell_h
|
||||||
|
}) = self.rendered[self.page].img
|
||||||
else {
|
else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if zoom.level < 0 {
|
||||||
|
img_area = Rect {
|
||||||
|
width: img_area.width.saturating_sub((zoom.level * 2).unsigned_abs()).max(1),
|
||||||
|
x: img_area.x + (zoom.level.unsigned_abs().min(img_area.width / 2)),
|
||||||
|
..img_area
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ugh I don't like this logic. I wish we could simplify it.
|
// Ugh I don't like this logic. I wish we could simplify it.
|
||||||
let (cell_width, cell_height) = if area.width >= img_area.width
|
let (new_cell_width, new_cell_height) =
|
||||||
&& area.height >= img_area.height
|
if cell_w >= img_area.width && cell_h >= img_area.height {
|
||||||
{
|
|
||||||
(f32::from(img_area.width), f32::from(img_area.height))
|
(f32::from(img_area.width), f32::from(img_area.height))
|
||||||
} else {
|
} else {
|
||||||
let img_width = f32::from(area.width);
|
let img_width = f32::from(cell_w);
|
||||||
let img_height = f32::from(area.height);
|
let img_height = f32::from(cell_h);
|
||||||
let available_to_real_width_ratio = f32::from(img_area.width) / img_width;
|
let img_area_width = f32::from(img_area.width);
|
||||||
let available_to_real_height_ratio =
|
let img_area_height = f32::from(img_area.height);
|
||||||
f32::from(img_area.height) / img_height;
|
let available_to_real_width_ratio = img_area_width / img_width;
|
||||||
|
let available_to_real_height_ratio = img_area_height / img_height;
|
||||||
|
|
||||||
if available_to_real_width_ratio > available_to_real_height_ratio {
|
if available_to_real_width_ratio > available_to_real_height_ratio {
|
||||||
(img_width, img_height / available_to_real_width_ratio)
|
(img_width, img_area_height / available_to_real_width_ratio)
|
||||||
} else {
|
} else {
|
||||||
(img_width / available_to_real_height_ratio, img_height)
|
(img_area_width / available_to_real_height_ratio, img_height)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let width = (cell_width * f32::from(font_size.0)) as u32;
|
log::debug!("new_cell stuff is {new_cell_width}x{new_cell_height}");
|
||||||
let height = (cell_height * f32::from(font_size.1)) as u32;
|
|
||||||
|
let width = (new_cell_width * f32::from(font_size.0)) as u32;
|
||||||
|
let height = (new_cell_height * f32::from(font_size.1)) as u32;
|
||||||
|
|
||||||
self.last_render = LastRender {
|
self.last_render = LastRender {
|
||||||
rect: size,
|
rect: size,
|
||||||
@@ -230,10 +243,10 @@ impl Tui {
|
|||||||
|
|
||||||
zoom.cell_pan_from_left = zoom
|
zoom.cell_pan_from_left = zoom
|
||||||
.cell_pan_from_left
|
.cell_pan_from_left
|
||||||
.min(area.width.saturating_sub(cell_width as u16));
|
.min(cell_w.saturating_sub(new_cell_width as u16));
|
||||||
zoom.cell_pan_from_top = zoom
|
zoom.cell_pan_from_top = zoom
|
||||||
.cell_pan_from_top
|
.cell_pan_from_top
|
||||||
.min(area.height.saturating_sub(cell_height as u16));
|
.min(cell_h.saturating_sub(new_cell_height as u16));
|
||||||
|
|
||||||
return KittyDisplay::DisplayImages(vec![KittyReadyToDisplay {
|
return KittyDisplay::DisplayImages(vec![KittyReadyToDisplay {
|
||||||
img,
|
img,
|
||||||
@@ -271,7 +284,7 @@ impl Tui {
|
|||||||
take
|
take
|
||||||
})
|
})
|
||||||
// and map it to their width (in cells on the terminal, not pixels)
|
// and map it to their width (in cells on the terminal, not pixels)
|
||||||
.filter_map(|(_, page)| page.img.as_mut().map(|img| (img.area().width, img)))
|
.filter_map(|(_, page)| page.img.as_mut().map(|img| (img.w_h().0, img)))
|
||||||
// and then take them as long as they won't overflow the available area.
|
// and then take them as long as they won't overflow the available area.
|
||||||
.take_while(|(width, _)| match test_area_w.checked_sub(*width) {
|
.take_while(|(width, _)| match test_area_w.checked_sub(*width) {
|
||||||
Some(new_val) => {
|
Some(new_val) => {
|
||||||
@@ -336,7 +349,11 @@ impl Tui {
|
|||||||
frame.render_widget(Image::new(page_img), img_area);
|
frame.render_widget(Image::new(page_img), img_area);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
ConvertedImage::Kitty { img, area: _ } => Some((img, Position {
|
ConvertedImage::Kitty {
|
||||||
|
img,
|
||||||
|
cell_h: _,
|
||||||
|
cell_w: _
|
||||||
|
} => Some((img, Position {
|
||||||
x: img_area.x,
|
x: img_area.x,
|
||||||
y: img_area.y
|
y: img_area.y
|
||||||
}))
|
}))
|
||||||
@@ -396,7 +413,7 @@ impl Tui {
|
|||||||
if page_num >= self.page && page_num <= self.page + self.last_render.pages_shown {
|
if page_num >= self.page && page_num <= self.page + self.last_render.pages_shown {
|
||||||
self.last_render.rect = Rect::default();
|
self.last_render.rect = Rect::default();
|
||||||
} else {
|
} else {
|
||||||
let img_w = img.area().width;
|
let img_w = img.w_h().0;
|
||||||
if img_w <= self.last_render.unused_width {
|
if img_w <= self.last_render.unused_width {
|
||||||
let num_fit = self.last_render.unused_width / img_w;
|
let num_fit = self.last_render.unused_width / img_w;
|
||||||
if page_num >= self.page && (self.page + num_fit as usize) >= page_num {
|
if page_num >= self.page && (self.page + num_fit as usize) >= page_num {
|
||||||
@@ -632,6 +649,20 @@ impl Tui {
|
|||||||
self.last_render.rect = Rect::default();
|
self.last_render.rect = Rect::default();
|
||||||
Some(InputAction::SwitchRenderZoom(f_or_f))
|
Some(InputAction::SwitchRenderZoom(f_or_f))
|
||||||
}
|
}
|
||||||
|
'o' if self.is_kitty => {
|
||||||
|
if let Some(z) = &mut self.zoom {
|
||||||
|
z.level = z.level.saturating_add(1);
|
||||||
|
}
|
||||||
|
self.last_render.rect = Rect::default();
|
||||||
|
Some(InputAction::Redraw)
|
||||||
|
}
|
||||||
|
'O' if self.is_kitty => {
|
||||||
|
if let Some(z) = &mut self.zoom {
|
||||||
|
z.level = z.level.saturating_sub(1);
|
||||||
|
}
|
||||||
|
self.last_render.rect = Rect::default();
|
||||||
|
Some(InputAction::Redraw)
|
||||||
|
}
|
||||||
'L' if self.is_kitty => {
|
'L' if self.is_kitty => {
|
||||||
if let Some(z) = &mut self.zoom {
|
if let Some(z) = &mut self.zoom {
|
||||||
z.cell_pan_from_left = z.cell_pan_from_left.saturating_add(1);
|
z.cell_pan_from_left = z.cell_pan_from_left.saturating_add(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user