use std::io::{self, Write as _};
use katui_proto::kitty::{
Format, IdSpace, ImageId as KittyImage, Place, PlacementId as KittyPlacement, Relative,
Transmit,
};
use katui_proto::placeholder::placeholder_row;
use katui_scene::cell::Position;
use crate::cells::move_cursor;
const ANCHOR_IMAGE: u32 = 0x00ff_fff0;
const ANCHOR_PLACEMENT: KittyPlacement = KittyPlacement(1);
const TRANSPARENT_PIXEL: [u8; 4] = [0; 4];
#[derive(Debug)]
pub(crate) struct Anchor {
image: KittyImage,
established: bool,
}
impl Anchor {
pub(crate) fn new(space: IdSpace) -> Self {
Self {
image: space.image(ANCHOR_IMAGE),
established: false,
}
}
pub(crate) fn forget(&mut self) {
self.established = false;
}
pub(crate) fn write(&mut self, bytes: &mut Vec<u8>) -> io::Result<()> {
if !self.established {
let transmit = Transmit::new(self.image, Format::Rgba, 1, 1, &TRANSPARENT_PIXEL);
for frame in transmit.encode()? {
bytes.write_all(&frame)?;
}
let mut place = Place::new(self.image);
place.placement = ANCHOR_PLACEMENT;
place.columns = 1;
place.rows = 1;
place.virtual_placement = true;
bytes.write_all(&place.encode())?;
self.established = true;
}
if let Some(cell) = placeholder_row(self.image, 0, 1) {
move_cursor(bytes, Position { x: 0, y: 0 })?;
bytes.write_all(cell.as_bytes())?;
}
Ok(())
}
pub(crate) fn offset_to(&self, origin: Position) -> Relative {
Relative {
image: self.image,
placement: ANCHOR_PLACEMENT,
columns: i32::from(origin.x),
rows: i32::from(origin.y),
}
}
}
#[cfg(test)]
mod tests {
use katui_scene::cell::Position;
use super::Anchor;
#[test]
fn the_anchor_image_goes_out_once_and_its_cell_every_frame() {
let mut anchor = Anchor::new(katui_proto::kitty::IdSpace::of_process(4242));
let (mut first, mut second) = (Vec::new(), Vec::new());
anchor
.write(&mut first)
.expect("writing to a Vec cannot fail");
anchor
.write(&mut second)
.expect("writing to a Vec cannot fail");
let first = String::from_utf8_lossy(&first);
let second = String::from_utf8_lossy(&second);
assert!(first.contains("a=t,") && first.contains("U=1"));
assert!(!second.contains("\x1b_G"), "the image is already there");
assert!(second.contains('\u{10eeee}'), "the cell is drawn again");
let offset = anchor.offset_to(Position { x: 5, y: 3 });
assert_eq!((offset.columns, offset.rows), (5, 3));
}
}