use super::run;
use crate::cell::Side;
use crate::{Arm, Cell, Orientation, Pos, Shape, Stroke, StrokeCell, Surface};
#[derive(Debug)]
pub(crate) struct Border {
pub(crate) from: Pos,
pub(crate) len: u16,
pub(crate) side: Side,
pub(crate) stroke: Stroke,
pub(crate) closes_interior: bool,
}
impl Shape for Border {
fn draw(&self, surface: &mut dyn Surface) {
let orientation = match self.side {
Side::Top | Side::Bottom => Orientation::Horizontal,
Side::Left | Side::Right => Orientation::Vertical,
};
let opposite = match self.side {
Side::Top => Side::Bottom,
Side::Right => Side::Left,
Side::Bottom => Side::Top,
Side::Left => Side::Right,
};
let arm_toward = |side: Side| {
if side == self.side {
Arm::Unset
} else if side == opposite {
if self.closes_interior {
Arm::Closed
} else {
Arm::Unset
}
} else {
Arm::Set(self.stroke.clone())
}
};
let cell: Cell = StrokeCell {
base: self.stroke.clone(),
top: arm_toward(Side::Top),
right: arm_toward(Side::Right),
bottom: arm_toward(Side::Bottom),
left: arm_toward(Side::Left),
}
.into();
for at in run(self.from, self.len, orientation) {
surface.stamp(at, cell.clone());
}
}
}
#[cfg(test)]
mod tests {
use super::Border;
use crate::cell::Side;
use crate::{
Arm, Buffer, Cell, CellReader, FigureLayer, Pos, Shape, Size, StampMode, Stroke,
StrokeCell, Window,
};
#[test]
fn a_top_border_closes_toward_the_interior_and_leaves_its_own_side_unset() {
let mut buffer = Buffer::new(Window {
origin: Pos { x: 0, y: 0 },
size: Size {
width: 1,
height: 1,
},
});
let mut layer = FigureLayer::new(&mut buffer, StampMode::Above);
Border {
from: Pos { x: 0, y: 0 },
len: 1,
side: Side::Top,
stroke: Stroke::from("light"),
closes_interior: true,
}
.draw(&mut layer);
assert_eq!(
buffer.cell(Pos { x: 0, y: 0 }),
Some(&Cell::from(StrokeCell {
base: Stroke::from("light"),
top: Arm::Unset,
right: Arm::Set(Stroke::from("light")),
bottom: Arm::Closed,
left: Arm::Set(Stroke::from("light")),
}))
);
}
#[test]
fn a_left_border_closes_toward_the_interior_and_leaves_its_own_side_unset() {
let mut buffer = Buffer::new(Window {
origin: Pos { x: 0, y: 0 },
size: Size {
width: 1,
height: 1,
},
});
let mut layer = FigureLayer::new(&mut buffer, StampMode::Above);
Border {
from: Pos { x: 0, y: 0 },
len: 1,
side: Side::Left,
stroke: Stroke::from("light"),
closes_interior: true,
}
.draw(&mut layer);
assert_eq!(
buffer.cell(Pos { x: 0, y: 0 }),
Some(&Cell::from(StrokeCell {
base: Stroke::from("light"),
top: Arm::Set(Stroke::from("light")),
right: Arm::Closed,
bottom: Arm::Set(Stroke::from("light")),
left: Arm::Unset,
}))
);
}
#[test]
fn a_border_writes_every_position_of_its_run() {
let mut buffer = Buffer::new(Window {
origin: Pos { x: 0, y: 0 },
size: Size {
width: 3,
height: 1,
},
});
let mut layer = FigureLayer::new(&mut buffer, StampMode::Above);
Border {
from: Pos { x: 0, y: 0 },
len: 3,
side: Side::Top,
stroke: Stroke::from("light"),
closes_interior: true,
}
.draw(&mut layer);
for x in 0..3 {
assert_eq!(
buffer.cell(Pos { x, y: 0 }),
Some(&Cell::from(StrokeCell {
base: Stroke::from("light"),
top: Arm::Unset,
right: Arm::Set(Stroke::from("light")),
bottom: Arm::Closed,
left: Arm::Set(Stroke::from("light")),
})),
"position ({x}, 0)"
);
}
}
#[test]
fn a_border_with_no_interior_to_close_leaves_that_side_unset() {
let mut buffer = Buffer::new(Window {
origin: Pos { x: 0, y: 0 },
size: Size {
width: 1,
height: 1,
},
});
let mut layer = FigureLayer::new(&mut buffer, StampMode::Above);
Border {
from: Pos { x: 0, y: 0 },
len: 1,
side: Side::Top,
stroke: Stroke::from("light"),
closes_interior: false,
}
.draw(&mut layer);
assert_eq!(
buffer.cell(Pos { x: 0, y: 0 }),
Some(&Cell::from(StrokeCell {
base: Stroke::from("light"),
top: Arm::Unset,
right: Arm::Set(Stroke::from("light")),
bottom: Arm::Unset,
left: Arm::Set(Stroke::from("light")),
}))
);
}
}