#[path = "previews/mod.rs"]
mod previews;
use blaeck::prelude::*;
use crossterm::event::{poll, read, Event, KeyCode};
use std::time::{Duration, Instant};
use previews::plasma::{
build_display, build_info, LavaLamp, Mode, Params, DEFAULT_HEIGHT, DEFAULT_WIDTH,
};
fn main() -> std::io::Result<()> {
let mut blaeck = Blaeck::new(std::io::stdout())?;
let start = Instant::now();
let seed = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(12345);
let mut params = Params::new(seed);
let mut lava = LavaLamp::new(params.num_blobs, seed);
let mut show_info = true;
let mut last_time = start.elapsed().as_secs_f64();
let (mut width, mut height) = crossterm::terminal::size()
.map(|(w, h)| (w as usize, h as usize))
.unwrap_or((DEFAULT_WIDTH + 4, DEFAULT_HEIGHT + 4));
width = width.saturating_sub(4).clamp(40, DEFAULT_WIDTH);
height = height.saturating_sub(4).clamp(10, DEFAULT_HEIGHT);
crossterm::terminal::enable_raw_mode()?;
loop {
if poll(Duration::from_millis(30))? {
match read()? {
Event::Resize(w, h) => {
width = (w as usize).saturating_sub(4).clamp(40, DEFAULT_WIDTH);
height = (h as usize).saturating_sub(4).clamp(10, DEFAULT_HEIGHT);
let _ = blaeck.handle_resize(w, h);
}
Event::Key(key) => {
match key.code {
KeyCode::Char('q') | KeyCode::Esc => break,
KeyCode::Char('c')
if key
.modifiers
.contains(crossterm::event::KeyModifiers::CONTROL) =>
{
break
}
KeyCode::Char('m') | KeyCode::Tab => {
params.mode = match params.mode {
Mode::Plasma => {
params.theme_idx = 7;
Mode::LavaLamp
}
Mode::LavaLamp => {
params.theme_idx = 0;
Mode::Plasma
}
};
}
KeyCode::Char('t') | KeyCode::Right => params.next_theme(),
KeyCode::Char('T') | KeyCode::Left => params.prev_theme(),
KeyCode::Char('p') | KeyCode::Down => params.next_preset(),
KeyCode::Char('P') | KeyCode::Up => params.prev_preset(),
KeyCode::Char(c @ '1'..='8') => {
params.apply_preset((c as usize) - ('1' as usize))
}
KeyCode::Char('r') => {
params.seed = params.seed.wrapping_add(1);
if params.mode == Mode::Plasma {
params.randomize_plasma();
} else {
lava = LavaLamp::new(params.num_blobs, params.seed);
}
}
KeyCode::Char('b') => {
params.num_blobs = (params.num_blobs + 2).min(20);
lava = LavaLamp::new(params.num_blobs, params.seed);
}
KeyCode::Char('B') => {
params.num_blobs = (params.num_blobs.saturating_sub(2)).max(2);
lava = LavaLamp::new(params.num_blobs, params.seed);
}
KeyCode::Char('i') => show_info = !show_info,
KeyCode::Char('+') | KeyCode::Char('=') => {
params.speed = (params.speed + 0.1).min(5.0)
}
KeyCode::Char('-') | KeyCode::Char('_') => {
params.speed = (params.speed - 0.1).max(0.1)
}
KeyCode::Char('z') | KeyCode::Char('[') => {
params.zoom = (params.zoom * 0.85).max(0.1)
}
KeyCode::Char('Z') | KeyCode::Char(']') => {
params.zoom = (params.zoom * 1.15).min(5.0)
}
_ => {}
}
}
_ => {}
}
}
let now = start.elapsed().as_secs_f64();
let raw_dt = now - last_time;
last_time = now;
if params.mode == Mode::LavaLamp {
lava.update(raw_dt, params.speed);
}
let time = now * params.speed;
let display = build_display(width, height, time, ¶ms, &lava);
let content = if show_info {
let info = build_info(¶ms);
element! {
Box(flex_direction: FlexDirection::Row) {
Box(border_style: BorderStyle::Round, border_color: Color::Rgb(100, 60, 160)) {
#(display)
}
#(info)
}
}
} else {
element! {
Box(border_style: BorderStyle::Round, border_color: Color::Rgb(100, 60, 160)) {
#(display)
}
}
};
let help = match params.mode {
Mode::Plasma => {
"m:lava t/T:theme p/P:preset 1-8:presets r:random +/-:speed i:info q:quit"
}
Mode::LavaLamp => "m:plasma t/T:theme z/Z:zoom +/-:speed i:info q:quit",
};
blaeck.render(element! {
Box(flex_direction: FlexDirection::Column) {
#(content)
Text(content: help, dim: true)
}
})?;
}
crossterm::terminal::disable_raw_mode()?;
blaeck.unmount()?;
println!("\nMode: {:?} | Theme: {}", params.mode, params.theme().name);
Ok(())
}