use rs3a;
use std::io::{stdout, Write};
use crossterm::{
terminal,
ExecutableCommand, QueueableCommand,
cursor, style::{self, Stylize}, self
};
use crossterm::event::{poll, read, Event};
use std::time::Duration;
fn is_bold(color: rs3a::Color) -> bool {
match color {
rs3a::Color::GRAY => {true}
rs3a::Color::BRIGHT_BLUE => {true}
rs3a::Color::BRIGHT_GREEN => {true}
rs3a::Color::BRIGHT_CYAN => {true}
rs3a::Color::BRIGHT_RED => {true}
rs3a::Color::BRIGHT_MAGENTA => {true}
rs3a::Color::BRIGHT_YELLOW => {true}
rs3a::Color::BRIGHT_WHITE => {true}
_ => {false}
}
}
fn to_color(color: rs3a::Color) -> style::Color {
match color {
rs3a::Color::BLACK => {style::Color::Black}
rs3a::Color::BLUE => {style::Color::DarkBlue}
rs3a::Color::GREEN => {style::Color::DarkGreen}
rs3a::Color::CYAN => {style::Color::DarkCyan}
rs3a::Color::RED => {style::Color::DarkRed}
rs3a::Color::MAGENTA => {style::Color::DarkMagenta}
rs3a::Color::YELLOW => {style::Color::DarkYellow}
rs3a::Color::WHITE => {style::Color::Grey}
rs3a::Color::GRAY => {style::Color::DarkGrey}
rs3a::Color::BRIGHT_BLUE => {style::Color::Blue}
rs3a::Color::BRIGHT_GREEN => {style::Color::Green}
rs3a::Color::BRIGHT_CYAN => {style::Color::Cyan}
rs3a::Color::BRIGHT_RED => {style::Color::Red}
rs3a::Color::BRIGHT_MAGENTA => {style::Color::Magenta}
rs3a::Color::BRIGHT_YELLOW => {style::Color::Yellow}
rs3a::Color::BRIGHT_WHITE => {style::Color::White}
}
}
pub fn render_fragment(fragment: rs3a::RowFragment) -> String {
let mut ret = fragment.text;
if let Some(fg) = fragment.fg_color {
ret = format!("{}", ret.with(to_color(fg)));
if is_bold(fg){
ret = format!("{}", ret.bold());
}
}
if let Some(bg) = fragment.bg_color {
ret = format!("{}", ret.on(to_color(bg)));
}
ret
}
pub fn render_frame(frame: rs3a::Frame) -> String {
let mut ret = String::new();
for row in frame {
for fragment in row{
ret += &render_fragment(fragment);
}
ret.push('\n');
}
ret
}
pub fn render(frames: Vec<rs3a::Frame>) -> Vec<String> {
let mut ret = Vec::new();
for frame in frames {
ret.push(render_frame(frame));
}
ret
}
pub fn render_raw_mod(frames: Vec<rs3a::Frame>) -> Vec<Vec<String>> {
let r = render(frames);
let mut ret = Vec::new();
for fr in r {
let mut frame = Vec::new();
for s in fr.split("\n"){
frame.push(s.to_string());
}
ret.push(frame);
}
ret
}
pub fn get_title(title: Option<String>, author: Option<String>) -> Option<String>{
if title == None && author == None { return None }
let mut ret = String::new();
if let Some(s) = title {
ret += &s;
}
if let Some(s) = author {
if ret != "" {
ret = format!("\"{}\" by ", ret);
}
ret += &s;
}
Some(ret)
}
pub fn play(art: rs3a::Art, lx: u16, ly: u16) -> crossterm::Result<()>{
let mut stdout = stdout();
stdout.execute(cursor::Hide)?;
terminal::enable_raw_mode()?;
if let Some(title) = get_title(art.header.title, art.header.author) {
stdout.execute(terminal::SetTitle(title))?;
}
for _ in 0..art.header.height {
print!("\n");
}
let (_, mut sy) = cursor::position()?;
sy -= art.header.height;
sy += ly;
let frames = render_raw_mod(art.body.frames);
let d = Duration::from_millis(art.header.delay as u64);
let l = frames.len()-1;
'outer: loop {
for (i, frame) in (&frames).iter().enumerate() {
for (i, row) in (&frame).iter().enumerate() {
stdout
.queue(cursor::MoveTo(lx,sy+i as u16))?
.queue(style::Print(row))?;
}
stdout.flush()?;
if i >= l {
if !art.header.loop_enable {break 'outer;}
}
if poll(d)? {
match read()? {
Event::Key(_) => {break 'outer;}
_ => {}
}
}
}
}
terminal::disable_raw_mode()?;
stdout.execute(cursor::Show)?;
Ok(())
}