Files
TerminalBasic/crates/tb-ui/examples/spike.rs

128 lines
4.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Phase-0-Spike: 80×25-Bildschirmpuffer, 16-Farben-Palette, Unicode,
//! Tastatur- und Mausereignisse.
//!
//! Start: `cargo run -p tb-ui --features terminal --example spike -- --log events.txt` — Beenden mit Esc.
//! Getippte Zeichen erscheinen im Eingabebereich; Sondertasten und
//! Mausereignisse werden in der Statuszeile angezeigt.
use crossterm::event::{self, Event, KeyCode, KeyEventKind};
use std::io::{stdout, Write};
use std::time::Duration;
use tb_ui::screen::{ScreenWidget, TextScreen};
fn testbild(s: &mut TextScreen) {
s.set_color(15, 1);
s.print(&format!(
"{:^80}",
"Terminal Basic — Phase-0-Spike (Esc beendet)"
));
// Farbraster: alle Vordergrundfarben auf allen Hintergründen
for bg in 0u8..8 {
s.set_color(15, 0);
s.locate(3 + bg as usize, 3).unwrap();
s.print(&format!("HG {bg} "));
for fg in 0u8..16 {
s.set_color(fg, bg);
s.print(&format!(" {fg:2}"));
}
}
// Unicode statt CP437: Rahmen, Umlaute, Symbole
s.set_color(14, 0);
s.locate(12, 3).unwrap();
s.print("┌─ Unicode ────────────────────────────┐");
s.locate(13, 3).unwrap();
s.print("│ Äpfel, Öl, Übermaß, ß — ☃ ♥ ♦ ♣ ♠ π λ │");
s.locate(14, 3).unwrap();
s.print("└──────────────────────────────────────┘");
s.set_color(7, 0);
s.locate(16, 3).unwrap();
s.print("Eingabe (Zeichen erscheinen hier):");
s.locate(17, 3).unwrap();
}
fn status(s: &mut TextScreen, text: &str) {
let (r, c) = (s.csrlin(), s.pos());
let (row, width) = (s.rows(), s.cols());
s.set_color(0, 7);
s.locate(row, 1).unwrap();
s.print(&format!("{text:<width$.width$}"));
s.set_color(7, 0);
s.locate(r, c).unwrap();
}
fn main() -> anyhow::Result<()> {
let args: Vec<_> = std::env::args_os().skip(1).collect();
anyhow::ensure!(
args.is_empty() || (args.len() == 2 && args[0] == "--log"),
"Aufruf: spike [--log neue-datei]"
);
let mut log = if args.len() == 2 {
Some(
std::fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(&args[1])?,
)
} else {
None
};
let _guard = tb_ui::terminal::TerminalGuard::enter(stdout())?;
let mut terminal = ratatui::Terminal::new(ratatui::backend::CrosstermBackend::new(stdout()))?;
let mut sequence = 0u64;
let (tw, th) = crossterm::terminal::size()?;
let mut screen = TextScreen::with_size(tw as usize, th as usize);
testbild(&mut screen);
status(&mut screen, "Bereit. Tasten/Maus testen, Esc beendet.");
loop {
terminal.draw(|f| f.render_widget(ScreenWidget(&screen), f.area()))?;
if !event::poll(Duration::from_millis(100))? {
continue;
}
let received = event::read()?;
sequence += 1;
if let Some(log) = &mut log {
writeln!(log, "{sequence}: {received:?}")?;
}
match received {
Event::Key(k) if k.kind != KeyEventKind::Release => match k.code {
KeyCode::Esc => break,
KeyCode::Char(c) => {
screen.print(&c.to_string());
status(
&mut screen,
&format!("Taste: {:?} Modifier: {:?}", k.code, k.modifiers),
);
}
KeyCode::Enter => screen.print("\n"),
other => status(
&mut screen,
&format!("Sondertaste: {other:?} Modifier: {:?}", k.modifiers),
),
},
Event::Mouse(m) => {
status(
&mut screen,
&format!(
"Maus: {:?} bei Spalte {}, Zeile {}",
m.kind,
m.column + 1,
m.row + 1
),
);
}
Event::Resize(w, h) => {
screen.resize(w as usize, h as usize);
status(&mut screen, &format!("Resize: {w}x{h}"));
}
_ => {}
}
}
Ok(())
}