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())
}
}
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
@@ -637,6 +695,8 @@ impl Tui {
InputAction::JumpingToPage(new_page)
}
let can_zoom = self.is_kitty && self.zoom.is_some();
match ev {
Event::Key(key) => {
match key.code {
@@ -653,7 +713,7 @@ impl Tui {
self.bottom_msg
{
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);
return Some(InputAction::Redraw);
}
@@ -762,24 +822,13 @@ impl Tui {
self.last_render.rect = Rect::default();
Some(InputAction::SwitchRenderZoom(f_or_f))
}
'o' if self.is_kitty =>
self.update_zoom(|z| z.level = z.level.saturating_add(1)),
'O' if self.is_kitty =>
self.update_zoom(|z| z.level = z.level.saturating_sub(1)),
'L' if self.is_kitty => self.update_zoom(|z| {
z.cell_pan_from_left = z.cell_pan_from_left.saturating_add(1);
}),
'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),
'o' if can_zoom => self.update_zoom(Zoom::step_in),
'O' if can_zoom => self.update_zoom(Zoom::step_out),
'L' if can_zoom => self.update_zoom(|z| z.pan(Direction::Right)),
'H' if can_zoom => self.update_zoom(|z| z.pan(Direction::Left)),
'J' if can_zoom => self.update_zoom(|z| z.pan(Direction::Down)),
'K' if can_zoom => self.update_zoom(|z| z.pan(Direction::Up)),
'G' if can_zoom => self.update_zoom(Zoom::pan_top),
_ => None
}
}
@@ -866,29 +915,36 @@ impl Tui {
}
}
Event::Mouse(mouse) => {
if mouse.modifiers.contains(KeyModifiers::CONTROL)
&& self.is_kitty
&& self.zoom.is_some()
{
match mouse.kind {
MouseEventKind::ScrollUp =>
self.update_zoom(|z| z.level = z.level.saturating_add(1).min(0)),
MouseEventKind::ScrollDown =>
self.update_zoom(|z| z.level = z.level.saturating_sub(1)),
_ => None
}
} else {
match mouse.kind {
MouseEventKind::ScrollRight =>
self.change_page(PageChange::Next, ChangeAmount::Single),
MouseEventKind::ScrollDown =>
self.change_page(PageChange::Next, ChangeAmount::WholeScreen),
MouseEventKind::ScrollLeft =>
self.change_page(PageChange::Prev, ChangeAmount::Single),
MouseEventKind::ScrollUp =>
self.change_page(PageChange::Prev, ChangeAmount::WholeScreen),
_ => None
let mut handle_scroll = |mut direction: Direction| {
if can_zoom {
if mouse.modifiers.contains(KeyModifiers::CONTROL) {
match direction {
Direction::Up => self.update_zoom(Zoom::step_in),
Direction::Down => self.update_zoom(Zoom::step_out),
_ => None
}
} else {
if mouse.modifiers.contains(KeyModifiers::SHIFT) {
direction = direction.flip_mouse_xy();
}
self.update_zoom(|z| z.pan(direction))
}
} else {
let (change, amount) = match direction {
Direction::Right => (PageChange::Next, ChangeAmount::Single),
Direction::Down => (PageChange::Next, ChangeAmount::WholeScreen),
Direction::Left => (PageChange::Prev, ChangeAmount::Single),
Direction::Up => (PageChange::Prev, ChangeAmount::WholeScreen)
};
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),