use crate::{Cmp, Position2, RegionS2, TermGrid, whilst};
#[inline] #[rustfmt::skip]
const fn clip_region(region: RegionS2<usize>, width: usize, height: usize)
-> Option<(usize, usize, usize, usize)> {
let [x, y] = region.pos.dim;
let [w, h] = region.ext.dim;
if x >= width || y >= height || w == 0 || h == 0 { return None; }
let x1 = Cmp(x.saturating_add(w)).min(width);
let y1 = Cmp(y.saturating_add(h)).min(height);
Some((x, y, x1, y1))
}
#[rustfmt::skip]
impl<E: Copy, S: AsRef<[E]> + AsMut<[E]>> TermGrid<E, S> {
pub fn fill_region(&mut self, region: RegionS2<usize>, element: impl Into<E>) {
let Some((x0, y0, x1, y1)) = clip_region(region, self.width(), self.height())
else { return; };
let element = element.into();
whilst! { y in y0,..y1; {
self.row_mut(y).unwrap()[x0..x1].fill(element);
}}
}
pub fn hline(&mut self, x: usize, y: usize, len: usize, element: impl Into<E>) {
self.fill_region(RegionS2::from(((x, y), (len, 1))), element);
}
pub fn vline(&mut self, x: usize, y: usize, len: usize, element: impl Into<E>) {
self.fill_region(RegionS2::from(((x, y), (1, len))), element);
}
pub fn frame(&mut self, region: RegionS2<usize>, element: impl Into<E>) {
let [x, y] = region.pos.dim;
let [w, h] = region.ext.dim;
if w == 0 || h == 0 { return; }
let element = element.into();
self.hline(x, y, w, element);
if h > 1 { self.hline(x, y.saturating_add(h - 1), w, element); }
if h > 2 {
let inner_y = y.saturating_add(1);
self.vline(x, inner_y, h - 2, element);
if w > 1 { self.vline( x.saturating_add(w - 1), inner_y, h - 2, element); }
}
}
}
#[rustfmt::skip]
impl<E: Copy, D> TermGrid<E, D> where D: AsRef<[E]> + AsMut<[E]> {
pub fn blit_at<S>(&mut self, source: &TermGrid<E, S>, destination: Position2<usize>)
where S: AsRef<[E]> {
self.blit_region_at(source,
RegionS2::from(((0, 0), (source.width(), source.height()))), destination);
}
pub fn blit_region_at<S>(&mut self, source: &TermGrid<E, S>,
source_region: RegionS2<usize>, destination: Position2<usize>) where S: AsRef<[E]> {
let [src_x, src_y] = source_region.pos.dim;
let [req_w, req_h] = source_region.ext.dim;
let [dst_x, dst_y] = destination.dim;
if src_x >= source.width() || src_y >= source.height()
|| dst_x >= self.width() || dst_y >= self.height() { return; }
let width = req_w.min(source.width() - src_x).min(self.width() - dst_x);
let height = req_h.min(source.height() - src_y).min(self.height() - dst_y);
if width == 0 || height == 0 { return; }
whilst! { y in 0..height; {
let src = &source.row(src_y + y).unwrap()[src_x..src_x + width];
let dst = &mut self.row_mut(dst_y + y).unwrap()[dst_x..dst_x + width];
dst.copy_from_slice(src);
}}
}
}