use std::{io, time::Duration};
use crossterm::event::{self, Event, KeyCode, KeyEventKind};
use scrin::{
Color, Terminal,
layout::{Constraint, Direction, Layout},
widgets::{
Paragraph, Widget,
block::{Block, BorderStyle},
},
};
use scrin_widgets::{AislingExt, AislingPalette, GlyphRain, NebulaGauge, SignalPanel};
fn main() -> io::Result<()> {
let mut terminal = Terminal::init()?;
let result = run(&mut terminal);
terminal.restore()?;
result
}
fn run(terminal: &mut Terminal) -> io::Result<()> {
let mut tick = 0_u64;
loop {
terminal.draw(|frame| {
let root = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(6),
Constraint::Min(10),
Constraint::Length(7),
])
.split(frame.area());
let buffer = frame.buffer();
let header = bordered_block("scrin-widgets", AislingPalette::cypherpunk().pulse);
let header_inner = header.inner(root[0]);
header.render(buffer, root[0]);
Paragraph::new("Scrin Widgets ships ambient fields, luminous progress, signal panels, and Aisling effects that decorate any Scrin widget. Press q or Esc to leave the dream.")
.with_word_wrap(true)
.aisling()
.tick(tick)
.palette(AislingPalette::cypherpunk())
.intensity(6)
.render(buffer, header_inner);
let middle = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(58), Constraint::Percentage(42)])
.split(root[1]);
GlyphRain::new(tick)
.density(42)
.palette(AislingPalette::phosphor())
.block(bordered_block(
"ambient glyph stream",
AislingPalette::phosphor().mid,
))
.render(buffer, middle[0]);
SignalPanel::new("aisling relay")
.line("phase: lucid")
.line("carrier: 8.13 THz")
.line("noise: below horizon")
.line("mode: exotic TUI")
.tick(tick)
.palette(AislingPalette::flare())
.render(buffer, middle[1]);
let lower = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
.split(root[2]);
let wave = ((tick % 100) as f64 / 100.0 - 0.5).abs();
let ratio = 1.0 - wave * 2.0;
NebulaGauge::new(ratio)
.tick(tick)
.label(format!("charge {:>3}%", (ratio * 100.0) as u16))
.block(bordered_block("gauge", AislingPalette::cypherpunk().low))
.render(buffer, lower[0]);
let wrapper = bordered_block("wrapper", AislingPalette::cypherpunk().pulse);
let wrapper_inner = wrapper.inner(lower[1]);
wrapper.render(buffer, lower[1]);
Paragraph::new(
"The Aisling wrapper is intentionally generic: render your own widget first, then let scrin-widgets tint the buffer.",
)
.with_word_wrap(true)
.aisling()
.tick(tick + 19)
.palette(AislingPalette::cypherpunk())
.intensity(5)
.render(buffer, wrapper_inner);
})?;
if event::poll(Duration::from_millis(33))? {
if let Event::Key(key) = event::read()? {
if key.kind == KeyEventKind::Press
&& matches!(key.code, KeyCode::Char('q') | KeyCode::Esc)
{
break;
}
}
}
tick = tick.wrapping_add(1);
}
Ok(())
}
fn bordered_block(title: &str, color: Color) -> Block<'_> {
Block::new(title)
.with_borders(BorderStyle::Plain)
.with_border_color(color)
.with_inner_margin(scrin::Rect::ZERO)
}