lool/examples/widget_grid_selector.rs

188 lines
5.2 KiB
Rust

use std::io;
use {
lool::tui::widgets::gridselector::GridItem,
ratatui::{
layout::{Alignment, Constraint, Direction, Layout},
style::{Modifier, Style, Stylize},
widgets::Paragraph,
},
};
use {
crossterm::{
event::{self, Event, KeyCode, KeyEvent, KeyEventKind},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
},
lool::tui::widgets::gridselector::{GridSelector, GridSelectorState},
ratatui::{layout::Rect, prelude::CrosstermBackend, style::Color, Frame, Terminal},
};
struct Item {
name: String,
emoji: String,
}
impl Item {
fn new(name: &str, emoji: &str) -> Self {
Item {
name: name.to_string(),
emoji: emoji.to_string(),
}
}
}
impl From<Item> for GridItem {
fn from(val: Item) -> Self {
GridItem::new(format!("{} {}", val.name, val.emoji))
}
}
fn main() -> io::Result<()> {
let stdout = io::stdout();
let mut stdout = stdout.lock();
enable_raw_mode()?;
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut term = Terminal::new(backend)?;
// Run the draw loop
run(&mut term)?;
disable_raw_mode()?;
execute!(term.backend_mut(), LeaveAlternateScreen)?;
term.show_cursor()?;
Ok(())
}
fn run<B>(term: &mut Terminal<B>) -> io::Result<()>
where
B: ratatui::backend::Backend,
{
// vec![
// "feat ✨".to_string(),
// "fix".to_string(),
// "chore".to_string(),
// "docs".to_string(),
// "style".to_string(),
// "refactor".to_string(),
// "perf".to_string(),
// "test".to_string(),
// "build".to_string(),
// "ci".to_string(),
// "revert".to_string(),
// "release".to_string(),
// "wip".to_string(),
// ]
let items = vec![
Item::new("feat", ""),
Item::new("fix", "🐛"),
Item::new("chore", "🧹"),
Item::new("docs", "📚"),
Item::new("style", "💅"),
Item::new("refactor", "🔨"),
Item::new("perf", "🐎"),
Item::new("test", "🚨"),
Item::new("build", "👷"),
Item::new("ci", "🔧"),
Item::new("revert", ""),
Item::new("release", "🚀"),
Item::new("wip", "🚧"),
];
let mut grid_state = GridSelectorState::new(items).columns(5);
loop {
term.draw(|f| draw(f, f.area(), &mut grid_state))?;
match event::read()? {
Event::Key(key) => match key {
KeyEvent {
code: KeyCode::Esc, ..
} => break,
KeyEvent {
code: KeyCode::Right,
kind: KeyEventKind::Press,
..
} => grid_state.move_right(),
KeyEvent {
code: KeyCode::Left,
kind: KeyEventKind::Press,
..
} => grid_state.move_left(),
KeyEvent {
code: KeyCode::Up,
kind: KeyEventKind::Press,
..
} => grid_state.move_up(),
KeyEvent {
code: KeyCode::Down,
kind: KeyEventKind::Press,
..
} => grid_state.move_down(),
KeyEvent {
code: KeyCode::Home,
kind: KeyEventKind::Press,
..
} => grid_state.move_to_row_start(),
KeyEvent {
code: KeyCode::End,
kind: KeyEventKind::Press,
..
} => grid_state.move_to_row_end(),
// selection
KeyEvent {
code: KeyCode::Enter,
kind: KeyEventKind::Press,
..
} => grid_state.select(),
_ => false,
},
_ => false,
};
}
Ok(())
}
fn draw(f: &mut Frame<'_>, area: Rect, state: &mut GridSelectorState) {
// vertical layout with 2 rows
let layout = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Min(0),
Constraint::Length(2),
Constraint::Length(1),
Constraint::Length(2),
])
.split(area);
f.render_stateful_widget(
GridSelector::default().with_selected_color(Color::Magenta),
layout[0],
state,
);
let selected = state.selected().unwrap_or(GridItem::new("None"));
let hovered = state.hovered().unwrap_or(GridItem::new("None"));
let ps = Paragraph::new(selected)
.alignment(Alignment::Center)
.alignment(Alignment::Center)
.style(Style::default().fg(Color::Magenta));
let ph = Paragraph::new(hovered)
.alignment(Alignment::Center)
.style(Style::default().fg(Color::Blue));
f.render_widget(
Paragraph::new("Hovered/Selected")
.alignment(Alignment::Center)
.add_modifier(Modifier::BOLD),
layout[1],
);
f.render_widget(ph, layout[2]);
f.render_widget(ps, layout[3]);
}