Improve panning behavior

This commit is contained in:
Max Dexheimer
2025-12-04 14:49:33 +01:00
committed by Max
parent d5d62c81a3
commit 19030f7fd4
+97 -41
View File
@@ -102,6 +102,64 @@ impl Zoom {
ZOOM_RATE_GRANULAR.powi(self.level.into()) ZOOM_RATE_GRANULAR.powi(self.level.into())
} }
} }
fn step_in(&mut self) {
self.level = self.level.saturating_add(1);
}
fn step_out(&mut self) {
self.level = self.level.saturating_sub(1);
}
// TODO: Make this configurable, maybe allow fractional steps?
// With fractional steps, it might also be a good idea to have these
// have the same ratio as the font aspect ratio.
const PAN_STEP_X: i16 = 2;
const PAN_STEP_Y: i16 = 1;
fn pan(&mut self, direction: Direction) {
let (target, sign) = match direction {
Direction::Up => (&mut self.cell_pan_from_top, -1),
Direction::Down => (&mut self.cell_pan_from_top, 1),
Direction::Left => (&mut self.cell_pan_from_left, -1),
Direction::Right => (&mut self.cell_pan_from_left, 1)
};
let step = if direction.is_vertical() {
Self::PAN_STEP_Y
} else {
Self::PAN_STEP_X
};
*target = target.saturating_add_signed(sign * step);
}
fn pan_bottom(&mut self) {
self.cell_pan_from_top = 0;
}
fn pan_top(&mut self) {
self.cell_pan_from_top = u16::MAX;
}
}
#[derive(Clone, Copy, Debug)]
enum Direction {
Up,
Down,
Left,
Right
}
impl Direction {
/// Flips the directions for vertical and horizonal panning.
fn flip_mouse_xy(self) -> Self {
match self {
Self::Up => Self::Left,
Self::Left => Self::Up,
Self::Down => Self::Right,
Self::Right => Self::Down
}
}
fn is_vertical(self) -> bool {
match self {
Self::Up | Self::Down => true,
Self::Left | Self::Right => false
}
}
} }
// This seems like a kinda weird struct because it holds two optionals but any representation // This seems like a kinda weird struct because it holds two optionals but any representation
@@ -637,6 +695,8 @@ impl Tui {
InputAction::JumpingToPage(new_page) InputAction::JumpingToPage(new_page)
} }
let can_zoom = self.is_kitty && self.zoom.is_some();
match ev { match ev {
Event::Key(key) => { Event::Key(key) => {
match key.code { match key.code {
@@ -653,7 +713,7 @@ impl Tui {
self.bottom_msg self.bottom_msg
{ {
if c == 'g' && self.is_kitty { if c == 'g' && self.is_kitty {
self.update_zoom(|z| z.cell_pan_from_top = 0); self.update_zoom(Zoom::pan_bottom);
self.set_msg(MessageSetting::Pop); self.set_msg(MessageSetting::Pop);
return Some(InputAction::Redraw); return Some(InputAction::Redraw);
} }
@@ -762,24 +822,13 @@ 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 => 'o' if can_zoom => self.update_zoom(Zoom::step_in),
self.update_zoom(|z| z.level = z.level.saturating_add(1)), 'O' if can_zoom => self.update_zoom(Zoom::step_out),
'O' if self.is_kitty => 'L' if can_zoom => self.update_zoom(|z| z.pan(Direction::Right)),
self.update_zoom(|z| z.level = z.level.saturating_sub(1)), 'H' if can_zoom => self.update_zoom(|z| z.pan(Direction::Left)),
'L' if self.is_kitty => self.update_zoom(|z| { 'J' if can_zoom => self.update_zoom(|z| z.pan(Direction::Down)),
z.cell_pan_from_left = z.cell_pan_from_left.saturating_add(1); 'K' if can_zoom => self.update_zoom(|z| z.pan(Direction::Up)),
}), 'G' if can_zoom => self.update_zoom(Zoom::pan_top),
'H' if self.is_kitty => self.update_zoom(|z| {
z.cell_pan_from_left = z.cell_pan_from_left.saturating_sub(1);
}),
'J' if self.is_kitty => self.update_zoom(|z| {
z.cell_pan_from_top = z.cell_pan_from_top.saturating_add(1);
}),
'K' if self.is_kitty => self.update_zoom(|z| {
z.cell_pan_from_top = z.cell_pan_from_top.saturating_sub(1);
}),
'G' if self.is_kitty =>
self.update_zoom(|z| z.cell_pan_from_top = u16::MAX),
_ => None _ => None
} }
} }
@@ -866,29 +915,36 @@ impl Tui {
} }
} }
Event::Mouse(mouse) => { Event::Mouse(mouse) => {
if mouse.modifiers.contains(KeyModifiers::CONTROL) let mut handle_scroll = |mut direction: Direction| {
&& self.is_kitty if can_zoom {
&& self.zoom.is_some() if mouse.modifiers.contains(KeyModifiers::CONTROL) {
{ match direction {
match mouse.kind { Direction::Up => self.update_zoom(Zoom::step_in),
MouseEventKind::ScrollUp => Direction::Down => self.update_zoom(Zoom::step_out),
self.update_zoom(|z| z.level = z.level.saturating_add(1).min(0)), _ => None
MouseEventKind::ScrollDown => }
self.update_zoom(|z| z.level = z.level.saturating_sub(1)), } else {
_ => None if mouse.modifiers.contains(KeyModifiers::SHIFT) {
} direction = direction.flip_mouse_xy();
} else { }
match mouse.kind { self.update_zoom(|z| z.pan(direction))
MouseEventKind::ScrollRight => }
self.change_page(PageChange::Next, ChangeAmount::Single), } else {
MouseEventKind::ScrollDown => let (change, amount) = match direction {
self.change_page(PageChange::Next, ChangeAmount::WholeScreen), Direction::Right => (PageChange::Next, ChangeAmount::Single),
MouseEventKind::ScrollLeft => Direction::Down => (PageChange::Next, ChangeAmount::WholeScreen),
self.change_page(PageChange::Prev, ChangeAmount::Single), Direction::Left => (PageChange::Prev, ChangeAmount::Single),
MouseEventKind::ScrollUp => Direction::Up => (PageChange::Prev, ChangeAmount::WholeScreen)
self.change_page(PageChange::Prev, ChangeAmount::WholeScreen), };
_ => None self.change_page(change, amount)
} }
};
match mouse.kind {
MouseEventKind::ScrollRight => handle_scroll(Direction::Right),
MouseEventKind::ScrollDown => handle_scroll(Direction::Down),
MouseEventKind::ScrollLeft => handle_scroll(Direction::Left),
MouseEventKind::ScrollUp => handle_scroll(Direction::Up),
_ => None
} }
} }
Event::Resize(_, _) => Some(InputAction::Redraw), Event::Resize(_, _) => Some(InputAction::Redraw),