Phase 6: Plattformprüfungen und absolute RGB-Farben, Change 05 archivieren
This commit is contained in:
@@ -930,21 +930,7 @@ fn theme_rgb(color: ratatui::style::Color) -> (u8, u8, u8) {
|
||||
use ratatui::style::Color;
|
||||
match color {
|
||||
Color::Rgb(r, g, b) => (r, g, b),
|
||||
Color::Indexed(n @ 16..=231) => {
|
||||
let n = n - 16;
|
||||
let channel = |v: u8| if v == 0 { 0 } else { 55 + v * 40 };
|
||||
(channel(n / 36), channel(n / 6 % 6), channel(n % 6))
|
||||
}
|
||||
Color::Indexed(n @ 232..=255) => {
|
||||
let v = 8 + (n - 232) * 10;
|
||||
(v, v, v)
|
||||
}
|
||||
_ => {
|
||||
let n = (0..16)
|
||||
.find(|n| tb_ide::render::dos_color(*n, 16) == color)
|
||||
.unwrap_or_else(|| panic!("Unbestimmte IDE-Farbe: {color:?}"));
|
||||
theme_rgb(tb_ide::render::dos_color(n, u16::MAX))
|
||||
}
|
||||
_ => panic!("Keine absolute RGB-Farbe: {color:?}"),
|
||||
}
|
||||
}
|
||||
fn theme_contrast(fg: ratatui::style::Color, bg: ratatui::style::Color) -> f64 {
|
||||
@@ -983,23 +969,21 @@ fn assert_theme(app: &mut App, context: &str) {
|
||||
|
||||
#[test]
|
||||
fn theme_contrast_covers_rendered_states_and_rejects_bad_pairs() {
|
||||
use tb_ide::render::dos_color;
|
||||
for colors in [256, u16::MAX] {
|
||||
for (fg, bg) in tb_ide::options::Options::default().colors {
|
||||
assert!(theme_contrast(dos_color(fg, colors), dos_color(bg, colors)) >= 4.5);
|
||||
}
|
||||
assert!(theme_contrast(dos_color(15, colors), dos_color(7, colors)) < 4.5);
|
||||
for n in 0..16 {
|
||||
let fg = if matches!(n, 0 | 1 | 4 | 5 | 6 | 8 | 9) {
|
||||
15
|
||||
} else {
|
||||
0
|
||||
};
|
||||
assert!(
|
||||
theme_contrast(dos_color(fg, colors), dos_color(n, colors)) >= 4.5,
|
||||
"Palettenbeschriftung {n}"
|
||||
);
|
||||
}
|
||||
use tb_ide::render::dos;
|
||||
for (fg, bg) in tb_ide::options::Options::default().colors {
|
||||
assert!(theme_contrast(dos(fg), dos(bg)) >= 4.5);
|
||||
}
|
||||
assert!(theme_contrast(dos(15), dos(7)) < 4.5);
|
||||
for n in 0..16 {
|
||||
let fg = if matches!(n, 0 | 1 | 4 | 5 | 6 | 8 | 9) {
|
||||
15
|
||||
} else {
|
||||
0
|
||||
};
|
||||
assert!(
|
||||
theme_contrast(dos(fg), dos(n)) >= 4.5,
|
||||
"Palettenbeschriftung {n}"
|
||||
);
|
||||
}
|
||||
let t = Temp::new();
|
||||
let mut app = t.app();
|
||||
@@ -1086,34 +1070,23 @@ fn theme_color_commands_use_explicit_values_and_never_modify_terminal_palette()
|
||||
buffer::Cell,
|
||||
style::Color,
|
||||
};
|
||||
use tb_ide::render::dos_color;
|
||||
assert_eq!(dos_color(1, u16::MAX), Color::Rgb(0, 0, 170));
|
||||
assert_eq!(dos_color(5, u16::MAX), Color::Rgb(170, 0, 170));
|
||||
assert_eq!(dos_color(6, u16::MAX), Color::Rgb(170, 85, 0));
|
||||
for colors in [16, 256, u16::MAX] {
|
||||
for n in 0..16 {
|
||||
let color = dos_color(n, colors);
|
||||
if let Color::Indexed(index) = color {
|
||||
assert!(index >= 16);
|
||||
}
|
||||
let mut cell = Cell::default();
|
||||
cell.set_symbol("X")
|
||||
.set_bg(color)
|
||||
.set_fg(dos_color(15, colors));
|
||||
let mut output = Vec::new();
|
||||
CrosstermBackend::new(&mut output)
|
||||
.draw(std::iter::once((0, 0, &cell)))
|
||||
.unwrap();
|
||||
let sequence = String::from_utf8(output).unwrap();
|
||||
assert!(sequence.contains('X'));
|
||||
if colors >= 256 {
|
||||
assert!(sequence.contains("48;"));
|
||||
}
|
||||
if colors > 256 {
|
||||
assert!(sequence.contains("48;2;"));
|
||||
}
|
||||
assert!(!sequence.contains("\x1b]")); // Keine globale Palettenänderung.
|
||||
}
|
||||
use tb_ide::render::dos;
|
||||
assert_eq!(dos(1), Color::Rgb(0, 0, 170));
|
||||
assert_eq!(dos(5), Color::Rgb(170, 0, 170));
|
||||
assert_eq!(dos(6), Color::Rgb(170, 85, 0));
|
||||
for n in 0..16 {
|
||||
assert_eq!(dos(n), tb_ui::screen::basic_color(n));
|
||||
let mut cell = Cell::default();
|
||||
cell.set_symbol("X").set_bg(dos(n)).set_fg(dos(15));
|
||||
let mut output = Vec::new();
|
||||
CrosstermBackend::new(&mut output)
|
||||
.draw(std::iter::once((0, 0, &cell)))
|
||||
.unwrap();
|
||||
let sequence = String::from_utf8(output).unwrap();
|
||||
assert!(sequence.contains('X'));
|
||||
assert!(sequence.contains("38;2;255;255;255"));
|
||||
assert!(sequence.contains("48;2;"));
|
||||
assert!(!sequence.contains("\x1b]")); // Keine globale Palettenänderung.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1149,3 +1122,61 @@ fn theme_designer_chrome_and_handles_preserve_program_palette() {
|
||||
assert_theme(&mut app, "Designer-Werkzeug");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn theme_windows_erase_desktop_and_underlying_windows_on_every_redraw() {
|
||||
use ratatui::{
|
||||
layout::Rect,
|
||||
style::{Color, Modifier},
|
||||
};
|
||||
let t = Temp::new();
|
||||
let mut app = t.app();
|
||||
app.options.syntax_checking = false;
|
||||
// Ein sichtbares Zeichen macht das Durchscheinen sicher erkennbar.
|
||||
app.options.desktop = '@';
|
||||
type_text(&mut app, "PRINT 42");
|
||||
let mut term = Terminal::new(TestBackend::new(app.size.0, app.size.1)).unwrap();
|
||||
for selected in [false, true, false] {
|
||||
if selected {
|
||||
key(&mut app, K::Char('a'), M::CONTROL);
|
||||
} else {
|
||||
plain(&mut app, K::Right);
|
||||
}
|
||||
term.draw(|f| app.render(f)).unwrap();
|
||||
let b = term.backend().buffer();
|
||||
let rect = app.rect(app.windows.iter().find(|w| w.id == app.active).unwrap());
|
||||
let inner = Rect::new(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2);
|
||||
for y in inner.y..inner.bottom() {
|
||||
for x in inner.x..inner.right() {
|
||||
let c = &b[(x, y)];
|
||||
assert_ne!(c.symbol(), "@", "Desktop in Fenster bei {x}/{y}");
|
||||
assert_eq!(c.bg, Color::Rgb(0, 0, 170));
|
||||
if y > inner.y {
|
||||
assert_eq!(c.symbol(), " ", "Restinhalt bei {x}/{y}");
|
||||
assert!(!c.modifier.contains(Modifier::REVERSED));
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_eq!(b[(inner.x, inner.y)].symbol(), "P");
|
||||
assert_eq!(
|
||||
b[(inner.x, inner.y)].modifier.contains(Modifier::REVERSED),
|
||||
selected
|
||||
);
|
||||
}
|
||||
// Beim Aktivieren eines überlappenden Fensters müssen auch fremde Texte weg.
|
||||
app.execute(Command::NewModule);
|
||||
plain(&mut app, K::Enter);
|
||||
assert!(app.dialog.is_none());
|
||||
term.draw(|f| app.render(f)).unwrap();
|
||||
let b = term.backend().buffer();
|
||||
let rect = app.rect(app.windows.iter().find(|w| w.id == app.active).unwrap());
|
||||
for y in rect.y + 1..rect.bottom() - 1 {
|
||||
for x in rect.x + 1..rect.right() - 1 {
|
||||
assert_eq!(
|
||||
b[(x, y)].symbol(),
|
||||
" ",
|
||||
"Überdeckter Fensterinhalt bei {x}/{y}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user