scrollbar

This commit is contained in:
Robin Appelman 2024-07-25 22:28:43 +02:00
commit 7a9fb10037
2 changed files with 97 additions and 21 deletions

View file

@ -12,6 +12,7 @@ use ratatui::crossterm::terminal::{
};
use ratatui::crossterm::{event, ExecutableCommand};
use ratatui::prelude::*;
use ratatui::widgets::{Block, Borders, Scrollbar, ScrollbarOrientation};
use ratatui::Terminal;
use std::io;
use std::io::stdout;
@ -29,7 +30,7 @@ pub fn run_ui(app: App) -> Result<(), UiError> {
stdout().execute(EnterAlternateScreen)?;
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
let mut ui_state = UiState::default();
let mut ui_state = UiState::new(&app);
while !matches!(ui_state, UiState::Quit) {
terminal.draw(|frame| ui(frame, &app, &mut ui_state))?;
@ -79,7 +80,10 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
match state {
UiState::Quit => {}
UiState::MatchList { table_state } => {
UiState::MatchList {
table_state,
scroll_state,
} => {
let selected = table_state.selected().unwrap_or(0);
let histogram = if selected == 0 {
&app.all.histogram
@ -89,28 +93,75 @@ fn ui(frame: &mut Frame, app: &App, state: &mut UiState) {
} else {
&app.unmatched.histogram
};
let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some(""))
.end_symbol(Some(""));
frame.render_widget(UiHistogram::new(histogram), layout[0]);
frame.render_stateful_widget(match_list(app), layout[1], table_state);
frame.render_stateful_widget(
match_list(app).block(Block::new().borders(Borders::RIGHT)),
layout[1],
table_state,
);
frame.render_stateful_widget(
scrollbar,
layout[1].inner(Margin {
vertical: 1,
horizontal: 0,
}),
scroll_state,
);
frame.render_widget(footer(app, page), layout[2]);
}
UiState::Match {
result,
table_state,
scroll_state,
..
} => {
let selected_group = &result.grouped[table_state.selected().unwrap_or_default()];
let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some(""))
.end_symbol(Some(""));
frame.render_widget(UiHistogram::new(&selected_group.histogram), layout[0]);
frame.render_stateful_widget(grouped_lines(app, result), layout[1], table_state);
frame.render_stateful_widget(
grouped_lines(app, result).block(Block::new().borders(Borders::RIGHT)),
layout[1],
table_state,
);
frame.render_stateful_widget(
scrollbar,
layout[1].inner(Margin {
vertical: 1,
horizontal: 0,
}),
scroll_state,
);
frame.render_widget(footer(app, page), layout[2]);
}
UiState::Logs {
lines, table_state, ..
lines,
table_state,
scroll_state,
..
} => {
let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some(""))
.end_symbol(Some(""));
frame.render_stateful_widget(
raw_logs(app, lines),
raw_logs(app, lines).block(Block::new().borders(Borders::RIGHT)),
layout[0].union(layout[1]),
table_state,
);
frame.render_stateful_widget(
scrollbar,
layout[0].union(layout[1]).inner(Margin {
vertical: 1,
horizontal: 0,
}),
scroll_state,
);
frame.render_widget(footer(app, page), layout[2]);
}
}

View file

@ -1,34 +1,38 @@
use crate::app::{App, LogMatch};
use ratatui::widgets::TableState;
use ratatui::widgets::{ScrollbarState, TableState};
use table_state::TableStateExt;
#[derive(Clone)]
pub enum UiState<'a> {
MatchList {
table_state: TableState,
scroll_state: ScrollbarState,
},
Match {
result: &'a LogMatch,
table_state: TableState,
scroll_state: ScrollbarState,
previous: Box<UiState<'a>>,
},
Logs {
lines: &'a [usize],
table_state: TableState,
scroll_state: ScrollbarState,
previous: Box<UiState<'a>>,
},
Quit,
}
impl Default for UiState<'_> {
fn default() -> Self {
impl<'a> UiState<'a> {
pub fn new(app: &App) -> Self {
let mut table_state = TableState::default();
table_state.select(Some(0));
UiState::MatchList { table_state }
UiState::MatchList {
table_state,
scroll_state: ScrollbarState::new(app.match_lines()),
}
}
impl<'a> UiState<'a> {
pub fn page(&self) -> UiPage {
match self {
UiState::Quit | UiState::MatchList { .. } => UiPage::MatchList,
@ -39,13 +43,22 @@ impl<'a> UiState<'a> {
fn table_state(&mut self) -> Option<&mut TableState> {
match self {
UiState::MatchList { table_state } => Some(table_state),
UiState::MatchList { table_state, .. } => Some(table_state),
UiState::Match { table_state, .. } => Some(table_state),
UiState::Logs { table_state, .. } => Some(table_state),
UiState::Quit => None,
}
}
fn scroll_state(&mut self) -> Option<&mut ScrollbarState> {
match self {
UiState::MatchList { scroll_state, .. } => Some(scroll_state),
UiState::Match { scroll_state, .. } => Some(scroll_state),
UiState::Logs { scroll_state, .. } => Some(scroll_state),
UiState::Quit => None,
}
}
fn table_count(&self, app: &App) -> usize {
match self {
UiState::MatchList { .. } => app.match_lines(),
@ -63,20 +76,25 @@ impl<'a> UiState<'a> {
(mut state, UiEvent::Down(step)) => {
let count = state.table_count(app);
if let Some(table_state) = state.table_state() {
table_state.down(count, step)
let pos = table_state.down(count, step);
let scroll_state = state.scroll_state().unwrap();
*scroll_state = scroll_state.position(pos);
}
state
}
(mut state, UiEvent::Up(step)) => {
let count = state.table_count(app);
if let Some(table_state) = state.table_state() {
table_state.up(count, step)
let pos = table_state.up(count, step);
let scroll_state = state.scroll_state().unwrap();
*scroll_state = scroll_state.position(pos);
}
state
}
(
UiState::MatchList {
table_state: prev_state,
scroll_state: prev_scroll,
},
UiEvent::Select,
) => {
@ -94,14 +112,17 @@ impl<'a> UiState<'a> {
UiState::Match {
result,
table_state,
scroll_state: ScrollbarState::new(result.count()),
previous: Box::new(UiState::MatchList {
table_state: prev_state,
scroll_state: prev_scroll,
}),
}
}
(
UiState::Match {
table_state: prev_state,
scroll_state: prev_scroll,
previous,
result,
},
@ -115,8 +136,10 @@ impl<'a> UiState<'a> {
UiState::Logs {
lines,
table_state,
scroll_state: ScrollbarState::new(lines.len()),
previous: Box::new(UiState::Match {
table_state: prev_state,
scroll_state: prev_scroll,
previous,
result,
}),
@ -148,29 +171,31 @@ mod table_state {
use ratatui::widgets::TableState;
pub trait TableStateExt {
fn up(&mut self, count: usize, step: usize);
fn down(&mut self, count: usize, step: usize);
fn up(&mut self, count: usize, step: usize) -> usize;
fn down(&mut self, count: usize, step: usize) -> usize;
}
impl TableStateExt for TableState {
fn up(&mut self, count: usize, step: usize) {
fn up(&mut self, count: usize, step: usize) -> usize {
let current = self.selected().unwrap_or(0);
let after = if step > current {
count - 1
} else {
current - step
};
self.select(Some(after))
self.select(Some(after));
after
}
fn down(&mut self, count: usize, step: usize) {
fn down(&mut self, count: usize, step: usize) -> usize {
let current = self.selected().unwrap_or(0);
let after = if step >= count - current {
0
} else {
current + step
};
self.select(Some(after))
self.select(Some(after));
after
}
}
}