mirror of
https://github.com/itsjunetime/tdf.git
synced 2026-06-02 08:01:47 -04:00
Improve panning behavior
This commit is contained in:
+94
-38
@@ -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)),
|
|
||||||
MouseEventKind::ScrollDown =>
|
|
||||||
self.update_zoom(|z| z.level = z.level.saturating_sub(1)),
|
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match mouse.kind {
|
if mouse.modifiers.contains(KeyModifiers::SHIFT) {
|
||||||
MouseEventKind::ScrollRight =>
|
direction = direction.flip_mouse_xy();
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
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),
|
Event::Resize(_, _) => Some(InputAction::Redraw),
|
||||||
|
|||||||
Reference in New Issue
Block a user