ratatui/examples/modifiers.rs
Josh McKinney 6ad4bd4cf2
docs(examples): Add color and modifiers examples (#345)
The intent of these examples is to show the available colors and
modifiers.

- added impl Display for Color

![colors](https://vhs.charm.sh/vhs-2ZCqYbTbXAaASncUeWkt1z.gif)
![modifiers](https://vhs.charm.sh/vhs-2ovGBz5l3tfRGdZ7FCw0am.gif)
2023-08-11 01:36:12 +00:00

116 lines
3.6 KiB
Rust

/// This example is useful for testing how your terminal emulator handles different modifiers.
/// It will render a grid of combinations of foreground and background colors with all
/// modifiers applied to them.
use std::{
error::Error,
io::{self, Stdout},
iter::once,
result,
time::Duration,
};
use crossterm::{
event::{self, Event, KeyCode},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use itertools::Itertools;
use ratatui::{prelude::*, widgets::*};
type Result<T> = result::Result<T, Box<dyn Error>>;
fn main() -> Result<()> {
let mut terminal = setup_terminal()?;
let res = run_app(&mut terminal);
restore_terminal(terminal)?;
if let Err(err) = res {
eprintln!("{err:?}");
}
Ok(())
}
fn run_app<B: Backend>(terminal: &mut Terminal<B>) -> io::Result<()> {
loop {
terminal.draw(ui)?;
if event::poll(Duration::from_millis(250))? {
if let Event::Key(key) = event::read()? {
if let KeyCode::Char('q') = key.code {
return Ok(());
}
}
}
}
}
fn ui<B: Backend>(frame: &mut Frame<B>) {
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![Constraint::Length(1), Constraint::Min(0)])
.split(frame.size());
frame.render_widget(
Paragraph::new("Note: not all terminals support all modifiers")
.style(Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)),
layout[0],
);
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints(vec![Constraint::Length(1); 50])
.split(layout[1])
.iter()
.flat_map(|area| {
Layout::default()
.direction(Direction::Horizontal)
.constraints(vec![Constraint::Percentage(20); 5])
.split(*area)
.to_vec()
})
.collect_vec();
let colors = [
Color::Black,
Color::DarkGray,
Color::Gray,
Color::White,
Color::Red,
];
let all_modifiers = once(Modifier::empty())
.chain(Modifier::all().iter())
.collect_vec();
let mut index = 0;
for bg in colors.iter() {
for fg in colors.iter() {
for modifier in &all_modifiers {
let modifier_name = format!("{modifier:11?}");
let padding = (" ").repeat(12 - modifier_name.len());
let paragraph = Paragraph::new(Line::from(vec![
modifier_name.fg(*fg).bg(*bg).add_modifier(*modifier),
padding.fg(*fg).bg(*bg).add_modifier(*modifier),
// This is a hack to work around a bug in VHS which is used for rendering the
// examples to gifs. The bug is that the background color of a paragraph seems
// to bleed into the next character.
".".black().on_black(),
]));
frame.render_widget(paragraph, layout[index]);
index += 1;
}
}
}
}
fn setup_terminal() -> Result<Terminal<CrosstermBackend<Stdout>>> {
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
terminal.hide_cursor()?;
Ok(terminal)
}
fn restore_terminal(mut terminal: Terminal<CrosstermBackend<Stdout>>) -> Result<()> {
disable_raw_mode()?;
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
terminal.show_cursor()?;
Ok(())
}