use crossterm::{
cursor,
event::{self, Event, KeyCode, KeyModifiers},
execute,
terminal::{self, EnterAlternateScreen, LeaveAlternateScreen},
};
use scrin::core::buffer::Buffer;
use scrin::core::color::Color;
use scrin::core::rect::Rect;
use scrin::effects::LoaderPlayer;
use scrin::layout::{Constraint, Layout};
use scrin::status_bar::{StatusBar, StatusBarPosition};
use scrin::widgets::block::{Block, BorderStyle};
use scrin::widgets::Widget;
use std::io::{self, Write};
fn main() -> io::Result<()> {
let mut stdout = io::stdout();
terminal::enable_raw_mode()?;
execute!(stdout, EnterAlternateScreen, cursor::Hide)?;
let all_kinds = LoaderPlayer::all_kinds();
let grid_cols = 4;
let grid_rows = 4;
let page_size = (grid_cols * grid_rows) as usize;
let mut page = 0usize;
let mut tick: usize = 0;
let mut progress_val: f32 = 0.0;
let mut progress_dir: f32 = 0.02;
let mut status = StatusBar::new().with_position(StatusBarPosition::Bottom);
let result = (|| -> io::Result<()> {
loop {
let (cols, rows) = terminal::size()?;
let mut buffer = Buffer::new(cols as usize, rows as usize);
let outer = Rect::new(0, 0, cols, rows - 2);
let block = Block::new("Loader Demo — arrows navigate, j/k adjust progress, q quit")
.with_borders(BorderStyle::Rounded)
.with_border_color(Color::rgb(88, 166, 255));
block.render(&mut buffer, outer);
let inner = block.inner(outer);
let start = page * page_size;
let end = (start + page_size).min(all_kinds.len());
let count = end.saturating_sub(start);
let cols_count = grid_cols.min(count as u16);
let rows_count = grid_rows.min(((count as u16 + grid_cols - 1) / grid_cols).max(1));
let col_constraints: Vec<Constraint> = (0..cols_count)
.map(|_| Constraint::Percentage(100 / grid_cols))
.collect();
let row_constraints: Vec<Constraint> = (0..rows_count)
.map(|_| Constraint::Percentage(100 / grid_rows))
.collect();
let row_layout = Layout::vertical(row_constraints).margin(Rect::new(1, 1, 1, 1));
let row_rects = row_layout.split(inner);
for (row_idx, &row_rect) in row_rects.iter().enumerate() {
let col_layout = Layout::horizontal(col_constraints.clone());
let col_rects = col_layout.split(row_rect);
for (col_idx, &col_rect) in col_rects.iter().enumerate() {
let item_idx = row_idx * grid_cols as usize + col_idx;
if item_idx >= count {
break;
}
let kind = all_kinds[start + item_idx];
let loader = LoaderPlayer::new(kind);
let progress = LoaderPlayer::progress_from_fraction(progress_val);
let name = loader.name();
let mini_block = Block::new(name)
.with_borders(BorderStyle::Rounded)
.with_border_color(Color::rgb(48, 54, 61));
mini_block.render(&mut buffer, col_rect);
let inner_area = mini_block.inner(col_rect);
loader.render(tick, progress, &mut buffer, inner_area);
}
}
progress_val += progress_dir;
if progress_val >= 1.0 {
progress_val = 1.0;
progress_dir = -0.01;
} else if progress_val <= 0.0 {
progress_val = 0.0;
progress_dir = 0.02;
}
let total_pages = (all_kinds.len() + page_size - 1) / page_size;
status.set_left(
&format!("Loaders page {}/{}", page + 1, total_pages),
Color::rgb(88, 166, 255),
);
status.set_right(
&format!("Progress: {:.0}%", progress_val * 100.0),
Color::rgb(139, 148, 158),
);
let status_area = Rect::new(0, rows - 1, cols, 1);
status.render(&mut buffer, status_area);
write!(stdout, "\x1b[H{}", buffer.to_ansi_string())?;
stdout.flush()?;
if event::poll(std::time::Duration::from_millis(80))? {
if let Event::Key(key) = event::read()? {
match (key.modifiers, key.code) {
(KeyModifiers::CONTROL, KeyCode::Char('c'))
| (KeyModifiers::CONTROL, KeyCode::Char('q'))
| (_, KeyCode::Char('q')) => return Ok(()),
(_, KeyCode::Right) | (_, KeyCode::Char('l')) => {
if (page + 1) * page_size < all_kinds.len() {
page += 1;
}
}
(_, KeyCode::Left) | (_, KeyCode::Char('h')) => {
page = page.saturating_sub(1);
}
(_, KeyCode::Up) | (_, KeyCode::Char('k')) => {
progress_val = (progress_val + 0.1).min(1.0);
}
(_, KeyCode::Down) | (_, KeyCode::Char('j')) => {
progress_val = (progress_val - 0.1).max(0.0);
}
(_, KeyCode::Char('r')) => {
tick = 0;
progress_val = 0.0;
progress_dir = 0.02;
}
_ => {}
}
}
}
tick = tick.wrapping_add(1);
}
})();
execute!(stdout, cursor::Show, LeaveAlternateScreen)?;
terminal::disable_raw_mode()?;
result
}