mouse scroll

This commit is contained in:
Robin Appelman 2024-09-15 18:22:25 +02:00
commit ff4d270d02
3 changed files with 38 additions and 21 deletions

View file

@ -10,7 +10,7 @@ use crate::ui::single_match::grouped_lines;
use crate::ui::state::{ use crate::ui::state::{
ErrorState, LogState, LogsState, MatchListState, MatchState, UiEvent, UiPage, UiState, ErrorState, LogState, LogsState, MatchListState, MatchState, UiEvent, UiPage, UiState,
}; };
use ratatui::crossterm::event::{Event, KeyCode, KeyModifiers}; use ratatui::crossterm::event::{DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers, MouseEventKind};
use ratatui::crossterm::terminal::{ use ratatui::crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
}; };
@ -19,6 +19,7 @@ use ratatui::prelude::*;
use ratatui::Terminal; use ratatui::Terminal;
use std::io; use std::io;
use std::io::stdout; use std::io::stdout;
use std::time::Duration;
mod error_list; mod error_list;
mod footer; mod footer;
@ -34,6 +35,7 @@ mod table;
pub fn run_ui(app: App) -> Result<(), UiError> { pub fn run_ui(app: App) -> Result<(), UiError> {
enable_raw_mode()?; enable_raw_mode()?;
stdout().execute(EnterAlternateScreen)?; stdout().execute(EnterAlternateScreen)?;
stdout().execute(EnableMouseCapture)?;
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
terminal.clear().ok(); terminal.clear().ok();
@ -51,14 +53,15 @@ pub fn run_ui(app: App) -> Result<(), UiError> {
} }
disable_raw_mode()?; disable_raw_mode()?;
stdout().execute(DisableMouseCapture)?;
stdout().execute(LeaveAlternateScreen)?; stdout().execute(LeaveAlternateScreen)?;
Ok(()) Ok(())
} }
fn handle_events(page: UiPage) -> io::Result<Option<UiEvent>> { fn handle_events(page: UiPage) -> io::Result<Option<UiEvent>> {
if event::poll(std::time::Duration::from_millis(50))? { if event::poll(Duration::from_millis(50))? {
if let Event::Key(key) = event::read()? { match event::read()? {
if key.kind == event::KeyEventKind::Press { Event::Key(key) if key.kind == event::KeyEventKind::Press=> {
return Ok(match key.code { return Ok(match key.code {
KeyCode::Char('c') if key.modifiers == KeyModifiers::CONTROL => { KeyCode::Char('c') if key.modifiers == KeyModifiers::CONTROL => {
Some(UiEvent::Quit) Some(UiEvent::Quit)
@ -67,28 +70,38 @@ fn handle_events(page: UiPage) -> io::Result<Option<UiEvent>> {
KeyCode::Esc => Some(UiEvent::Back), KeyCode::Esc => Some(UiEvent::Back),
KeyCode::Char('e') if page == UiPage::MatchList => Some(UiEvent::Errors), KeyCode::Char('e') if page == UiPage::MatchList => Some(UiEvent::Errors),
KeyCode::Left if page != UiPage::MatchList => Some(UiEvent::Back), KeyCode::Left if page != UiPage::MatchList => Some(UiEvent::Back),
KeyCode::Down => Some(UiEvent::Down(1)), KeyCode::Down => Some(UiEvent::Down(1, true)),
KeyCode::Up => Some(UiEvent::Up(1)), KeyCode::Up => Some(UiEvent::Up(1, true)),
KeyCode::PageDown => Some(UiEvent::Down(10)), KeyCode::PageDown => Some(UiEvent::Down(10, false)),
KeyCode::PageUp => Some(UiEvent::Up(10)), KeyCode::PageUp => Some(UiEvent::Up(10, false)),
KeyCode::End => Some(UiEvent::Down(usize::MAX)), KeyCode::End => Some(UiEvent::Down(usize::MAX, false)),
KeyCode::Home => Some(UiEvent::Up(usize::MAX)), KeyCode::Home => Some(UiEvent::Up(usize::MAX, false)),
KeyCode::Enter | KeyCode::Right => Some(UiEvent::Select), KeyCode::Enter | KeyCode::Right => Some(UiEvent::Select),
KeyCode::Char('c') => Some(UiEvent::Copy), KeyCode::Char('c') => Some(UiEvent::Copy),
_ => None, _ => None,
}); });
} }
Event::Mouse(mouse) => {
return Ok(match mouse.kind {
MouseEventKind::ScrollUp => Some(UiEvent::Up(1, false)),
MouseEventKind::ScrollDown => Some(UiEvent::Down(1, false)),
_ => None,
})
},
_ => {}
} }
} }
Ok(None) Ok(None)
} }
const UI_HEADER_SIZE: u16 = 5;
fn ui(frame: &mut Frame, app: &App, state: &mut UiState) { fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
let page = state.page(); let page = state.page();
let layout = Layout::default() let layout = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.constraints(vec![ .constraints(vec![
Constraint::Min(5), Constraint::Length(UI_HEADER_SIZE),
Constraint::Percentage(100), Constraint::Percentage(100),
Constraint::Length(1), Constraint::Length(1),
]) ])

View file

@ -132,15 +132,15 @@ impl<'a> UiState<'a> {
(UiState::Quit, _) => (true, UiState::Quit), (UiState::Quit, _) => (true, UiState::Quit),
(_, UiEvent::Quit) => (true, UiState::Quit), (_, UiEvent::Quit) => (true, UiState::Quit),
(UiState::MatchList(_), UiEvent::Back) => (true, UiState::Quit), (UiState::MatchList(_), UiEvent::Back) => (true, UiState::Quit),
(mut state, UiEvent::Down(step)) => { (mut state, UiEvent::Down(step, rollover)) => {
if let Some(table_state) = state.table_state() { if let Some(table_state) = state.table_state() {
table_state.down(step); table_state.down(step, rollover);
} }
(true, state) (true, state)
} }
(mut state, UiEvent::Up(step)) => { (mut state, UiEvent::Up(step, rollover)) => {
if let Some(table_state) = state.table_state() { if let Some(table_state) = state.table_state() {
table_state.up(step); table_state.up(step, rollover);
} }
(true, state) (true, state)
} }
@ -254,8 +254,8 @@ impl<'a> UiState<'a> {
pub enum UiEvent { pub enum UiEvent {
Quit, Quit,
Back, Back,
Up(usize), Up(usize, bool),
Down(usize), Down(usize, bool),
Errors, Errors,
Select, Select,
Copy, Copy,

View file

@ -60,10 +60,14 @@ impl ScrollbarTableState {
self.table.selected().unwrap_or_default() self.table.selected().unwrap_or_default()
} }
pub fn up(&mut self, step: usize) -> usize { pub fn offset(&self) -> usize {
self.table.offset()
}
pub fn up(&mut self, step: usize, rollover: bool) -> usize {
let current = self.table.selected().unwrap_or(0); let current = self.table.selected().unwrap_or(0);
let after = if step > current { let after = if step > current {
if step == 1 { if rollover {
self.count - 1 self.count - 1
} else { } else {
0 0
@ -76,10 +80,10 @@ impl ScrollbarTableState {
after after
} }
pub fn down(&mut self, step: usize) -> usize { pub fn down(&mut self, step: usize, rollover: bool) -> usize {
let current = self.table.selected().unwrap_or(0); let current = self.table.selected().unwrap_or(0);
let after = if step >= self.count - current { let after = if step >= self.count - current {
if step == 1 { if rollover {
0 0
} else { } else {
self.count - 1 self.count - 1