| 1 | //! The shared braille renderer, promoted from the portable pet study's TUI. |
| 2 | //! It owns no clock, telemetry, or motion. The habitat owns placement and ink. |
| 3 | |
| 4 | use super::pet_sim::{PetSim, PetState, braille}; |
| 5 | use ratatui::{ |
| 6 | buffer::Buffer, |
| 7 | layout::Rect, |
| 8 | style::{Color, Style}, |
| 9 | widgets::Widget, |
| 10 | }; |
| 11 | |
| 12 | pub struct PetWidget<'a> { |
| 13 | pub sim: &'a PetSim, |
| 14 | pub state: &'a PetState, |
| 15 | } |
| 16 | |
| 17 | impl Widget for PetWidget<'_> { |
| 18 | fn render(self, area: Rect, buf: &mut Buffer) { |
| 19 | let frame = self.sim.frame; |
| 20 | let label = format!( |
| 21 | "{} · {}{}", |
| 22 | frame.channel, |
| 23 | frame.arch, |
| 24 | if frame.hollow { " · resting" } else { "" } |
| 25 | ); |
| 26 | // The creature and its non-colour cue are one unit. A narrow surface |
| 27 | // withholds both instead of silently dropping uncertainty or the gait. |
| 28 | if area.height < 4 || usize::from(area.width) < label.chars().count() { |
| 29 | return; |
| 30 | } |
| 31 | let tank = Rect { |
| 32 | height: area.height - 1, |
| 33 | ..area |
| 34 | }; |
| 35 | let grid = braille( |
| 36 | self.sim, |
| 37 | tank.width as usize, |
| 38 | tank.height as usize, |
| 39 | self.state, |
| 40 | ); |
| 41 | let fg = Color::Rgb( |
| 42 | (frame.r * frame.alpha).clamp(0.0, 255.0) as u8, |
| 43 | (frame.g * frame.alpha).clamp(0.0, 255.0) as u8, |
| 44 | (frame.b * frame.alpha).clamp(0.0, 255.0) as u8, |
| 45 | ); |
| 46 | render_grid(area, buf, &grid, &label, Style::default().fg(fg)); |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | /// Shared paint path for the Rust cameo and the embedded world's live raster. |
| 51 | /// A tiny viewport keeps the complete text cue before spending cells on dots. |
| 52 | pub(crate) fn render_grid(area: Rect, buf: &mut Buffer, grid: &[u8], label: &str, style: Style) { |
| 53 | codewhale_ratatui::BrailleFrame { |
| 54 | cells: grid, |
| 55 | caption: label, |
| 56 | style, |
| 57 | } |
| 58 | .render(area, buf); |
| 59 | } |
| 60 | |
| 61 | #[cfg(test)] |
| 62 | #[path = "pet_widget_legacy.rs"] |
| 63 | mod pet_widget_legacy; |
| 64 | #[cfg(test)] |
| 65 | #[path = "pet_widget_tests.rs"] |
| 66 | mod pet_widget_tests; |
| 67 |