use std::ops::Add;
use fatui::{
Event, InputState, KeyCode,
grid::Grid,
pos::{Size, X, Y},
};
use owo_colors::{AnsiColors, Style};
use rand::Rng;
fn main() {
let mut backend = fatui::open().expect("couldn't open a default backend");
let mut rng = rand::rng();
let mut _is = InputState::default();
let mut sparkles: Grid<usize> = Grid::new(Size::rnew(0, 0));
loop {
let mut frame = backend.step().unwrap().with(&mut _is);
sparkles.resize(frame.size());
match frame.input().event() {
Event::Close => break,
Event::KeyPress(KeyCode::Esc) => break,
Event::KeyPress(KeyCode::Char('c')) if frame.input().keys().ctrl() => break,
Event::Redraw => {
for y in frame.rows() {
for x in 0..frame.size().width.0 {
let x = X(x);
let val = sparkles.row(y).unwrap()[x];
if val > 0 {
sparkles.row_mut(y).unwrap()[x] -= 1;
frame.row(y)[x].char = rng.random_range(' '..'~');
frame.row(y)[x].style = Style::new().color(match rng.random_range(0..8) {
0 => AnsiColors::BrightBlack,
1 => AnsiColors::BrightRed,
2 => AnsiColors::BrightGreen,
3 => AnsiColors::BrightYellow,
4 => AnsiColors::BrightBlue,
5 => AnsiColors::BrightMagenta,
6 => AnsiColors::BrightCyan,
7 => AnsiColors::BrightWhite,
_ => unreachable!(),
});
} else {
frame.row(y)[x] = Default::default();
}
}
}
}
&Event::MouseMove(pos) => {
let xr = 2.max(frame.size().width.0 / 5);
let yr = 1.max(frame.size().height.0 / 10);
let radius = xr.min(yr) * 2;
let r2 = radius * radius;
let xmin = pos.x.0.saturating_sub(radius * 2);
let xmax = pos.x.0.add(radius * 2).min(frame.size().width.0);
let ymin = pos.y.0.saturating_sub(yr);
let ymax = pos.y.0.add(yr).min(frame.size().height.0);
for y in ymin..ymax {
for x in xmin..xmax {
let dist = (x.abs_diff(pos.x.0) / 2).pow(2) + y.abs_diff(pos.y.0).pow(2) + 1;
if dist > r2 {
continue;
}
let max = 20 * radius / dist;
let strength = rng.random_range(0..max);
if !rng.random_ratio(1, dist as u32 * dist as u32) {
continue;
}
sparkles.row_mut(Y(y)).unwrap()[X(x)] += strength;
}
}
}
_ => (),
}
}
}