75 lines
2.8 KiB
Rust
75 lines
2.8 KiB
Rust
//! Darstellung des Textbildschirms als Ratatui-Widget.
|
|
//!
|
|
//! Der Zellenpuffer selbst lebt in `tb_runtime::screen` (Entscheidung
|
|
//! 2026-09-03) — hier bleibt nur die Anbindung an das Terminal: die
|
|
//! Farbabbildung und das Widget. Da `Widget` und `TextScreen` beide fremd
|
|
//! sind, trägt das Widget ein Newtype.
|
|
|
|
pub use tb_runtime::screen::{Cell, TextScreen, MIN_COLS, MIN_ROWS};
|
|
|
|
use ratatui::buffer::Buffer;
|
|
use ratatui::layout::Rect;
|
|
use ratatui::style::{Color, Style};
|
|
use ratatui::widgets::Widget;
|
|
|
|
/// Abbildung der klassischen 16-Farben-Palette auf ANSI-Indexfarben.
|
|
/// (Klassisch: 1 = Blau, 4 = Rot — ANSI: 1 = Rot, 4 = Blau usw.)
|
|
pub fn basic_color(n: u8) -> Color {
|
|
const MAP: [u8; 16] = [0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15];
|
|
Color::Indexed(MAP[(n & 0x0F) as usize])
|
|
}
|
|
|
|
/// Zeichenbares Gegenstück zu [`TextScreen`].
|
|
pub struct ScreenWidget<'a>(pub &'a TextScreen);
|
|
|
|
/// Clipped viewport; only the terminal owner enforces physical minimum size.
|
|
impl Widget for ScreenWidget<'_> {
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
let cols = self.0.cols().min(area.width as usize);
|
|
let rows = self.0.rows().min(area.height as usize);
|
|
for row in 0..rows {
|
|
for col in 0..cols {
|
|
let c = self.0.cell(row + 1, col + 1);
|
|
if c.fortsetzung {
|
|
// Die Zelle gehört zum breiten Zeichen davor; das Terminal
|
|
// belegt sie beim Zeichnen selbst mit.
|
|
continue;
|
|
}
|
|
if let Some(cell) = buf.cell_mut((area.x + col as u16, area.y + row as u16)) {
|
|
let mut s = String::new();
|
|
s.push(c.ch);
|
|
cell.set_symbol(&s);
|
|
cell.set_style(Style::default().fg(basic_color(c.fg)).bg(basic_color(c.bg)));
|
|
}
|
|
}
|
|
}
|
|
// Cursor als invertierte Zelle darstellen (Terminal-Cursor wird in
|
|
// der Forms-/Runtime-Schicht später gezielt gesteuert).
|
|
if self.0.cursor_visible && self.0.csrlin() <= rows && self.0.pos() <= cols {
|
|
let (cx, cy) = (
|
|
area.x + (self.0.pos() - 1) as u16,
|
|
area.y + (self.0.csrlin() - 1) as u16,
|
|
);
|
|
if let Some(cell) = buf.cell_mut((cx, cy)) {
|
|
cell.set_style(
|
|
cell.style()
|
|
.add_modifier(ratatui::style::Modifier::REVERSED),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn farbabbildung() {
|
|
assert_eq!(basic_color(1), Color::Indexed(4)); // klassisch Blau
|
|
assert_eq!(basic_color(4), Color::Indexed(1)); // klassisch Rot
|
|
assert_eq!(basic_color(14), Color::Indexed(11)); // Gelb
|
|
assert_eq!(basic_color(15), Color::Indexed(15)); // Weiß
|
|
}
|
|
}
|