#![warn(
missing_docs,
clippy::all,
clippy::correctness,
clippy::suspicious,
clippy::style,
clippy::complexity,
clippy::perf,
clippy::pedantic,
clippy::cargo,
clippy::nursery
)]
mod legend;
#[cfg(feature = "kle")]
pub mod kle;
pub use legend::{Legend, Legends};
use geom::{Point, Rect, Size};
use color::Color;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Homing {
Scoop,
Bar,
Bump,
}
#[derive(Debug, Clone, Copy)]
pub enum Shape {
None(Size),
Normal(Size),
Space(Size),
Homing(Option<Homing>),
SteppedCaps,
IsoVertical,
IsoHorizontal,
}
impl Shape {
#[must_use]
pub fn outer_rect(self) -> Rect {
match self {
Self::None(size) | Self::Normal(size) | Self::Space(size) => {
Rect::from_origin_size(Point::ORIGIN, size)
}
Self::Homing(..) => Rect::from_origin_size(Point::ORIGIN, (1.0, 1.0)),
Self::SteppedCaps => Rect::from_origin_size(Point::ORIGIN, (1.75, 1.0)),
Self::IsoVertical | Self::IsoHorizontal => {
Rect::from_origin_size(Point::ORIGIN, (1.5, 2.0))
}
}
}
#[must_use]
pub fn inner_rect(self) -> Rect {
match self {
Self::None(size) | Self::Normal(size) | Self::Space(size) => {
Rect::from_origin_size(Point::ORIGIN, size)
}
Self::Homing(..) => Rect::from_origin_size(Point::ORIGIN, (1.0, 1.0)),
Self::SteppedCaps => Rect::from_origin_size(Point::ORIGIN, (1.25, 1.0)),
Self::IsoVertical => Rect::from_origin_size((0.25, 0.0), (1.25, 2.0)),
Self::IsoHorizontal => Rect::from_origin_size(Point::ORIGIN, (1.5, 1.0)),
}
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Key {
pub position: Point,
pub shape: Shape,
pub color: Color,
pub legends: Legends,
}
impl Key {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn example() -> Self {
Self {
legends: Legends::example(),
..Self::default()
}
}
}
impl Default for Key {
fn default() -> Self {
Self {
position: Point::ORIGIN,
shape: Shape::Normal(Size::new(1., 1.)),
color: Color::new(0.8, 0.8, 0.8),
legends: Legends::default(),
}
}
}
#[cfg(test)]
pub mod tests {
use assert_matches::assert_matches;
use super::*;
#[test]
fn shape_outer_size() {
assert_eq!(
Shape::Normal(Size::new(2.25, 1.)).outer_rect(),
Rect::new(0.0, 0.0, 2.25, 1.)
);
assert_eq!(
Shape::IsoVertical.outer_rect(),
Rect::new(0.0, 0.0, 1.5, 2.0)
);
assert_eq!(
Shape::IsoHorizontal.outer_rect(),
Rect::new(0.0, 0.0, 1.5, 2.0)
);
assert_eq!(
Shape::SteppedCaps.outer_rect(),
Rect::new(0.0, 0.0, 1.75, 1.0)
);
}
#[test]
fn shape_inner_size() {
assert_eq!(
Shape::Normal(Size::new(2.25, 1.)).inner_rect(),
Rect::new(0.0, 0.0, 2.25, 1.)
);
assert_eq!(
Shape::IsoVertical.inner_rect(),
Rect::new(0.25, 0.0, 1.5, 2.0)
);
assert_eq!(
Shape::IsoHorizontal.inner_rect(),
Rect::new(0.0, 0.0, 1.5, 1.0)
);
assert_eq!(
Shape::SteppedCaps.inner_rect(),
Rect::new(0.0, 0.0, 1.25, 1.0)
);
}
#[test]
fn key_new() {
let key = Key::new();
assert_eq!(key.position, Point::new(0., 0.));
assert_matches!(key.shape, Shape::Normal(size) if size == Size::new(1., 1.));
assert_eq!(key.color, Color::new(0.8, 0.8, 0.8));
for legend in key.legends {
assert!(legend.is_none());
}
}
#[test]
fn key_example() {
let key = Key::example();
let legend_is_some = [true, false, true, false, false, false, true, false, true];
assert_eq!(key.position, Point::new(0., 0.));
assert_matches!(key.shape, Shape::Normal(size) if size == Size::new(1., 1.));
assert_eq!(key.color, Color::new(0.8, 0.8, 0.8));
for (legend, is_some) in key.legends.into_iter().zip(legend_is_some) {
assert_eq!(legend.is_some(), is_some);
}
}
}