mirror of
https://github.com/ratatui/ratatui.git
synced 2025-09-27 04:50:46 +00:00

I was swayed by the arguments about this made by the compiler team In <https://github.com/rust-lang/compiler-team/issues/750> and decided to look at how this organization affects ratatui. I found this reduces the number of lines across the codebase by about 350 and makes the imports more readable and definitely more greppable as you usually only have to read a single line. I've found in the past that maintaining imports regularly leads to merge conflicts which have to be resolved by hand and this change should reduce the likelihood of that happening. Main change is in rustfmt.toml, and the rest is just the result of running `cargo xtask format`. While implementing this, cargo machete brings up that the various backend crates are unused by the example crates. The re-export of each backend crate under ratatui is to make it possible for libs that rely on a specific version of ratatui to use the same version of the backend crate. Apps in general should use the backend crate directly rather than through ratatui as this is less confusing. - Removes all usages of `ratatui::{crossterm, termion, termwiz}`` in the examples. - Adds the backend crate to the dependencies of the examples that use the backend crate directly.
132 lines
4.5 KiB
Rust
132 lines
4.5 KiB
Rust
//! # [Ratatui] `Scrollbar` example
|
|
//!
|
|
//! The latest version of this example is available in the [widget examples] folder in the
|
|
//! repository.
|
|
//!
|
|
//! Please note that the examples are designed to be run against the `main` branch of the Github
|
|
//! repository. This means that you may not be able to compile with the latest release version on
|
|
//! crates.io, or the one that you have installed locally.
|
|
//!
|
|
//! See the [examples readme] for more information on finding examples that match the version of the
|
|
//! library you are using.
|
|
//!
|
|
//! [Ratatui]: https://github.com/ratatui/ratatui
|
|
//! [widget examples]: https://github.com/ratatui/ratatui/blob/main/ratatui-widgets/examples
|
|
//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
|
|
|
|
use color_eyre::Result;
|
|
use crossterm::event::{self, Event, KeyCode};
|
|
use ratatui::layout::{Constraint, Layout, Margin, Rect};
|
|
use ratatui::style::{Color, Stylize};
|
|
use ratatui::symbols::scrollbar::Set;
|
|
use ratatui::text::{Line, Span};
|
|
use ratatui::widgets::{Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState};
|
|
use ratatui::{DefaultTerminal, Frame};
|
|
|
|
fn main() -> Result<()> {
|
|
color_eyre::install()?;
|
|
let terminal = ratatui::init();
|
|
let result = run(terminal);
|
|
ratatui::restore();
|
|
result
|
|
}
|
|
|
|
/// Run the application.
|
|
fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
|
let mut vertical = ScrollbarState::new(100);
|
|
let mut horizontal = ScrollbarState::new(100);
|
|
loop {
|
|
terminal.draw(|frame| draw(frame, &mut vertical, &mut horizontal))?;
|
|
if let Event::Key(key) = event::read()? {
|
|
match key.code {
|
|
KeyCode::Char('q') => break Ok(()),
|
|
KeyCode::Down | KeyCode::Char('j') => vertical.next(),
|
|
KeyCode::Up | KeyCode::Char('k') => vertical.prev(),
|
|
KeyCode::Right | KeyCode::Char('l') => horizontal.next(),
|
|
KeyCode::Left | KeyCode::Char('h') => horizontal.prev(),
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Draw the UI with vertical/horizontal scrollbars.
|
|
fn draw(frame: &mut Frame, vertical: &mut ScrollbarState, horizontal: &mut ScrollbarState) {
|
|
let vertical_layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
|
let [top, main] = vertical_layout.areas(frame.area());
|
|
|
|
let title = Line::from_iter([
|
|
Span::from("Scrollbar Widget").bold(),
|
|
Span::from(" (Press 'q' to quit, arrow keys to scroll)"),
|
|
]);
|
|
frame.render_widget(title.centered(), top);
|
|
|
|
render_content(frame, main, vertical, horizontal);
|
|
render_vertical_scrollbar(frame, main, vertical);
|
|
render_horizontal_scrollbar(frame, main, horizontal);
|
|
}
|
|
|
|
/// Render a vertical scrollbar on the right side of the area.
|
|
pub fn render_vertical_scrollbar(frame: &mut Frame, area: Rect, vertical: &mut ScrollbarState) {
|
|
let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight);
|
|
frame.render_stateful_widget(
|
|
scrollbar,
|
|
area.inner(Margin {
|
|
vertical: 1,
|
|
horizontal: 0,
|
|
}),
|
|
vertical,
|
|
);
|
|
}
|
|
|
|
/// Render a horizontal scrollbar at the bottom of the area.
|
|
pub fn render_horizontal_scrollbar(frame: &mut Frame, area: Rect, horizontal: &mut ScrollbarState) {
|
|
let scrollbar = Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
|
|
.symbols(Set {
|
|
track: "-",
|
|
thumb: "▮",
|
|
begin: "<",
|
|
end: ">",
|
|
})
|
|
.track_style(Color::Yellow)
|
|
.begin_style(Color::Green)
|
|
.end_style(Color::Red);
|
|
|
|
frame.render_stateful_widget(
|
|
scrollbar,
|
|
area.inner(Margin {
|
|
vertical: 0,
|
|
horizontal: 1,
|
|
}),
|
|
horizontal,
|
|
);
|
|
}
|
|
|
|
/// Render some content.
|
|
fn render_content(
|
|
frame: &mut Frame,
|
|
area: Rect,
|
|
vertical: &ScrollbarState,
|
|
horizontal: &ScrollbarState,
|
|
) {
|
|
let content = vec![
|
|
Line::from("This is a paragraph with a vertical and horizontal scrollbar."),
|
|
Line::from_iter(["Lorem ipsum dolor sit amet, consectetur adipiscing elit.".repeat(10)]),
|
|
Line::from_iter([
|
|
"Horizontal: ".bold(),
|
|
horizontal.get_position().to_string().yellow(),
|
|
]),
|
|
Line::from_iter([
|
|
"Vertical: ".bold(),
|
|
vertical.get_position().to_string().yellow(),
|
|
]),
|
|
];
|
|
frame.render_widget(
|
|
Paragraph::new(content).scroll((
|
|
vertical.get_position() as u16,
|
|
horizontal.get_position() as u16,
|
|
)),
|
|
area,
|
|
);
|
|
}
|