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::EffectPlayer;
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 kinds = EffectPlayer::all_kinds();
let mut current_index = 0;
let text = "scrin";
let mut player = EffectPlayer::new(kinds[current_index], text);
let mut tick: usize = 0;
let mut status = StatusBar::new().with_position(StatusBarPosition::Bottom);
let result = run_loop(
&mut stdout,
&mut current_index,
&mut player,
&mut tick,
&mut status,
text,
);
execute!(stdout, cursor::Show, LeaveAlternateScreen)?;
terminal::disable_raw_mode()?;
result
}
fn run_loop(
stdout: &mut io::Stdout,
current_index: &mut usize,
player: &mut EffectPlayer,
tick: &mut usize,
status: &mut StatusBar,
text: &str,
) -> io::Result<()> {
let kinds = EffectPlayer::all_kinds();
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("Effect Demo — left/right switch, r restart, 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 effect_area = Rect::new(
inner.x,
inner.y + 1,
inner.width,
inner.height.saturating_sub(2),
);
let info_text = format!(
" [{}/{}] {} ({} frames)",
*current_index + 1,
kinds.len(),
player.name(),
player.total_frames()
);
buffer.set_str(
inner.x as usize,
inner.y as usize,
&info_text,
Color::rgb(255, 178, 72),
None,
);
player.set_frame(*tick);
player.render_to_buffer(&mut buffer, effect_area);
status.set_left(
&format!("Effect: {}", player.name()),
Color::rgb(88, 166, 255),
);
status.set_right(
&format!("Frame {}/{}", *tick + 1, player.total_frames()),
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')) => {
*current_index = (*current_index + 1) % kinds.len();
*player = EffectPlayer::new(kinds[*current_index], text);
*tick = 0;
}
(_, KeyCode::Left) | (_, KeyCode::Char('h')) => {
*current_index = if *current_index == 0 {
kinds.len() - 1
} else {
*current_index - 1
};
*player = EffectPlayer::new(kinds[*current_index], text);
*tick = 0;
}
(_, KeyCode::Char('r')) => {
*tick = 0;
*player = EffectPlayer::new(kinds[*current_index], text);
}
_ => {}
}
}
}
*tick = tick.wrapping_add(1) % player.total_frames().max(1);
}
}