Skip to content

Commit

Permalink
Misc refactor of keyset-key
Browse files Browse the repository at this point in the history
  • Loading branch information
staticintlucas committed Dec 22, 2023
1 parent cdc7ccc commit b732336
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 139 deletions.
29 changes: 21 additions & 8 deletions keyset-drawing/src/imp/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ use super::{Outline, Path, ARC_TOL};

pub fn top(key: &key::Key, options: &Options) -> Path {
let path = match key.shape {
key::Shape::Normal(size) => options.profile.top_with_size(size).to_path(ARC_TOL),
key::Shape::SteppedCaps => options.profile.top_with_size((1.25, 1.)).to_path(ARC_TOL),
key::Shape::None(..) => BezPath::new(),
key::Shape::Normal(size) | key::Shape::Space(size) => {
options.profile.top_with_size(size).to_path(ARC_TOL)
}
key::Shape::Homing(..) => options.profile.top_with_size((1.0, 1.0)).to_path(ARC_TOL),
key::Shape::SteppedCaps => options.profile.top_with_size((1.25, 1.0)).to_path(ARC_TOL),
key::Shape::IsoHorizontal | key::Shape::IsoVertical => iso_top_path(&options.profile),
};

Expand All @@ -26,7 +30,14 @@ pub fn top(key: &key::Key, options: &Options) -> Path {

pub fn bottom(key: &key::Key, options: &Options) -> Path {
let path = match key.shape {
key::Shape::Normal(size) => options.profile.bottom_with_size(size).to_path(ARC_TOL),
key::Shape::None(..) => BezPath::new(),
key::Shape::Normal(size) | key::Shape::Space(size) => {
options.profile.bottom_with_size(size).to_path(ARC_TOL)
}
key::Shape::Homing(..) => options
.profile
.bottom_with_size((1.0, 1.0))
.to_path(ARC_TOL),
key::Shape::SteppedCaps => options
.profile
.bottom_with_size((1.75, 1.))
Expand All @@ -47,12 +58,14 @@ pub fn bottom(key: &key::Key, options: &Options) -> Path {
pub fn homing(key: &key::Key, options: &Options) -> Option<Path> {
let profile = &options.profile;

let key::Type::Homing(homing) = key.typ else {
let key::Shape::Homing(homing) = key.shape else {
return None;
};
let homing = homing.unwrap_or(profile.homing.default);

let center = profile.top_with_size(key.shape.margin().size()).center();
let center = profile
.top_with_size(key.shape.inner_rect().size())
.center();

let bez_path = match homing {
key::Homing::Scoop => None,
Expand Down Expand Up @@ -447,7 +460,7 @@ mod tests {
// Scoop
let scoop = {
let mut key = key::Key::example();
key.typ = key::Type::Homing(Some(key::Homing::Scoop));
key.shape = key::Shape::Homing(Some(key::Homing::Scoop));
key
};

Expand All @@ -457,7 +470,7 @@ mod tests {
// Bar
let bar = {
let mut key = key::Key::example();
key.typ = key::Type::Homing(Some(key::Homing::Bar));
key.shape = key::Shape::Homing(Some(key::Homing::Bar));
key
};

Expand All @@ -479,7 +492,7 @@ mod tests {
// Bump
let bump = {
let mut key = key::Key::example();
key.typ = key::Type::Homing(Some(key::Homing::Bump));
key.shape = key::Shape::Homing(Some(key::Homing::Bump));
key
};

Expand Down
13 changes: 3 additions & 10 deletions keyset-drawing/src/imp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod legend;
use std::collections::HashSet;

use ::key::Key;
use ::key::Shape as KeyShape;
use color::Color;
use geom::{BezPath, Point, Shape, Vec2};

Expand Down Expand Up @@ -33,22 +34,14 @@ pub struct KeyDrawing {

impl KeyDrawing {
pub fn new(key: &Key, options: &Options) -> Self {
let show_key = options.show_keys && !matches!(key.typ, ::key::Type::None);
let show_key = options.show_keys && !matches!(key.shape, KeyShape::None(..));

let bottom = show_key.then(|| key::bottom(key, options));
let top = show_key.then(|| key::top(key, options));
let step = show_key.then(|| key::step(key, options)).flatten();
let homing = show_key.then(|| key::homing(key, options)).flatten();

let top_rect = match key.shape {
::key::Shape::Normal(size) => options.profile.top_with_size(size).rect(),
::key::Shape::SteppedCaps => options.profile.top_with_size((1.25, 1.)).rect(),
::key::Shape::IsoHorizontal => options.profile.top_with_size((1.5, 1.)).rect(),
::key::Shape::IsoVertical => {
let rect = options.profile.top_with_size((1.25, 2.)).rect();
rect.with_origin(rect.origin() + (250., 0.))
}
};
let top_rect = options.profile.top_with_rect(key.shape.inner_rect()).rect();

let margin = options.show_margin.then(|| {
// TODO get unique margins, not size_idx's. Currently impossible because Insets: !Hash
Expand Down
2 changes: 1 addition & 1 deletion keyset-drawing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl Drawing {
pub fn new(keys: &[Key], options: &Options) -> Self {
let bounds = keys
.iter()
.map(|k| k.shape.bounds().with_origin(k.position))
.map(|k| k.shape.outer_rect().with_origin(k.position))
.fold(
Rect::from_origin_size(Point::ORIGIN, Size::new(1., 1.)),
|rect, key| rect.union(key),
Expand Down
2 changes: 1 addition & 1 deletion keyset-drawing/src/pdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ mod tests {
use crate::Options;

#[test]
fn test_to_svg() {
fn test_to_pdf() {
let options = Options {
show_margin: true, // to give us an unfilled path
..Default::default()
Expand Down
12 changes: 11 additions & 1 deletion keyset-key/src/kle/error.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
/// An error parsing a KLE layout
#[derive(Debug)]
pub enum Error {
/// An error in parsing the KLE JSON file
JsonParseError(serde_json::Error),
/// A key size not supported by `keyset`
UnsupportedKeySize {
/// The key's `w` value
w: f64,
/// The key's `h` value
h: f64,
/// The key's `x2` value
x2: f64,
/// The key's `y2` value
y2: f64,
/// The key's `w2` value
w2: f64,
/// The key's `h2` value
h2: f64,
},
JsonParseError(serde_json::Error),
}

impl std::fmt::Display for Error {
Expand Down Expand Up @@ -47,6 +56,7 @@ impl From<serde_json::Error> for Error {
}
}

/// A [`std::result::Result`] with [`Error`] as it's error type
pub type Result<T> = std::result::Result<T, Error>;

#[cfg(test)]
Expand Down
144 changes: 73 additions & 71 deletions keyset-key/src/kle/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
//! Load KLE layouts from JSON files
mod error;

use geom::{Point, Size};
use kle_serial as kle;

use crate::{Homing, Key, Legend, Shape, Type};
use crate::{Homing, Key, Legend, Shape};
pub use error::{Error, Result};

fn shape_from_kle(key: &kle::Key) -> Result<Shape> {
const STEP_CAPS: [f64; 6] = [1.25, 1.0, 0.0, 0.0, 1.75, 1.0];
const ISO_VERT: [f64; 6] = [1.25, 2.0, -0.25, 0.0, 1.5, 1.0];
const ISO_HORIZ: [f64; 6] = [1.5, 1.0, 0.25, 0.0, 1.25, 2.0];

fn is_close<const N: usize>(a: &[f64; N], b: &[f64; N]) -> bool {
a.iter().zip(b).all(|(a, b)| (b - a).abs() < 1e-2)
}
Expand All @@ -21,14 +27,31 @@ fn shape_from_kle(key: &kle::Key) -> Result<Shape> {
..
} = key;

if is_close(&[w, h, x2, y2, w2, h2], &[1.25, 1., 0., 0., 1.75, 1.]) {
let is_normal = is_close(&[x2, y2, w2, h2], &[0.0, 0.0, w, h]);
let is_1u = is_normal && is_close(&[w, h], &[1.0, 1.0]);

let dims = [w, h, x2, y2, w2, h2];

if is_1u && (key.profile.contains("scoop") || key.profile.contains("dish")) {
Ok(Shape::Homing(Some(Homing::Scoop)))
} else if is_1u && key.profile.contains("bar") {
Ok(Shape::Homing(Some(Homing::Bar)))
} else if is_1u && (key.profile.contains("bump") || key.profile.contains("dot")) {
Ok(Shape::Homing(Some(Homing::Bump)))
} else if is_normal && key.profile.contains("space") {
Ok(Shape::Space(Size::new(w, h)))
} else if is_1u && key.homing {
Ok(Shape::Homing(None))
} else if key.decal {
Ok(Shape::None(Size::new(w, h)))
} else if is_normal {
Ok(Shape::Normal(Size::new(w, h)))
} else if is_close(&dims, &STEP_CAPS) {
Ok(Shape::SteppedCaps)
} else if is_close(&[w, h, x2, y2, w2, h2], &[1.25, 2., -0.25, 0., 1.5, 1.]) {
} else if is_close(&dims, &ISO_VERT) {
Ok(Shape::IsoVertical)
} else if is_close(&[w, h, x2, y2, w2, h2], &[1.5, 1., 0.25, 0., 1.25, 2.]) {
} else if is_close(&dims, &ISO_HORIZ) {
Ok(Shape::IsoHorizontal)
} else if is_close(&[x2, y2, w2, h2], &[0., 0., w, h]) {
Ok(Shape::Normal(Size::new(w, h)))
} else {
// TODO support all key shapes/sizes
Err(Error::UnsupportedKeySize {
Expand All @@ -42,29 +65,6 @@ fn shape_from_kle(key: &kle::Key) -> Result<Shape> {
}
}

fn type_from_kle(key: &kle::Key) -> Type {
const SCOOP_KW: [&str; 2] = ["scoop", "dish"];
const BAR_KW: [&str; 2] = ["bar", "line"];
const BUMP_KW: [&str; 4] = ["bump", "dot", "nub", "nipple"];

// TODO support ghosted keys?
if SCOOP_KW.iter().any(|kw| key.profile.contains(kw)) {
Type::Homing(Some(Homing::Scoop))
} else if BAR_KW.iter().any(|kw| key.profile.contains(kw)) {
Type::Homing(Some(Homing::Bar))
} else if BUMP_KW.iter().any(|kw| key.profile.contains(kw)) {
Type::Homing(Some(Homing::Bump))
} else if key.profile.contains("space") {
Type::Space
} else if key.homing {
Type::Homing(None)
} else if key.decal {
Type::None
} else {
Type::Normal
}
}

impl From<kle::Legend> for Legend {
fn from(legend: kle::Legend) -> Self {
let kle::Legend { text, size, color } = legend;
Expand All @@ -82,7 +82,6 @@ impl TryFrom<kle::Key> for Key {
fn try_from(mut key: kle::Key) -> Result<Self> {
let position = Point::new(key.x + key.x2.min(0.), key.y + key.y2.min(0.));
let shape = shape_from_kle(&key)?;
let typ = type_from_kle(&key);
let color = key.color.rgb().into();
let legends = {
let mut arr = <[Option<kle::Legend>; 9]>::default();
Expand All @@ -93,13 +92,17 @@ impl TryFrom<kle::Key> for Key {
Ok(Self {
position,
shape,
typ,
color,
legends,
})
}
}

/// Loads a KLE layout from a JSON string into a [`Vec<Key>`]
///
/// # Errors
///
/// If an
pub fn from_json(json: &str) -> Result<Vec<Key>> {
let key_iter: kle::KeyIterator = serde_json::from_str(json)?;
key_iter.map(Key::try_from).collect()
Expand All @@ -114,6 +117,37 @@ mod tests {

#[test]
fn key_shape_from_kle() {
let default_key = shape_from_kle(&kle::Key::default()).unwrap();
let decal = shape_from_kle(&kle::Key {
decal: true,
..Default::default()
})
.unwrap();
let space = shape_from_kle(&kle::Key {
profile: "space".into(),
..Default::default()
})
.unwrap();
let homing_default = shape_from_kle(&kle::Key {
homing: true,
..Default::default()
})
.unwrap();
let homing_scoop = shape_from_kle(&kle::Key {
profile: "scoop".into(),
..Default::default()
})
.unwrap();
let homing_bar = shape_from_kle(&kle::Key {
profile: "bar".into(),
..Default::default()
})
.unwrap();
let homing_bump = shape_from_kle(&kle::Key {
profile: "bump".into(),
..Default::default()
})
.unwrap();
let regular_key = shape_from_kle(&kle::Key {
width: 2.25,
height: 1.,
Expand Down Expand Up @@ -155,7 +189,14 @@ mod tests {
})
.unwrap();

assert_matches!(regular_key, Shape::Normal(size) if size == Size::new(2.25, 1.));
assert_matches!(default_key, Shape::Normal(size) if size == Size::new(1.0, 1.0));
assert_matches!(regular_key, Shape::Normal(size) if size == Size::new(2.25, 1.0));
assert_matches!(decal, Shape::None(size) if size == Size::new(1.0, 1.0));
assert_matches!(space, Shape::Space(size) if size == Size::new(1.0, 1.0));
assert_matches!(homing_default, Shape::Homing(None));
assert_matches!(homing_scoop, Shape::Homing(Some(Homing::Scoop)));
assert_matches!(homing_bar, Shape::Homing(Some(Homing::Bar)));
assert_matches!(homing_bump, Shape::Homing(Some(Homing::Bump)));
assert_matches!(iso_horiz, Shape::IsoHorizontal);
assert_matches!(iso_vert, Shape::IsoVertical);
assert_matches!(step_caps, Shape::SteppedCaps);
Expand Down Expand Up @@ -184,45 +225,6 @@ mod tests {
);
}

#[test]
fn key_type_from_kle() {
let regular_key = type_from_kle(&kle::Key {
..Default::default()
});
let decal = type_from_kle(&kle::Key {
decal: true,
..Default::default()
});
let space = type_from_kle(&kle::Key {
profile: "space".into(),
..Default::default()
});
let homing_default = type_from_kle(&kle::Key {
homing: true,
..Default::default()
});
let homing_scoop = type_from_kle(&kle::Key {
profile: "scoop".into(),
..Default::default()
});
let homing_bar = type_from_kle(&kle::Key {
profile: "bar".into(),
..Default::default()
});
let homing_bump = type_from_kle(&kle::Key {
profile: "bump".into(),
..Default::default()
});

assert_matches!(regular_key, Type::Normal);
assert_matches!(decal, Type::None);
assert_matches!(space, Type::Space);
assert_matches!(homing_default, Type::Homing(None));
assert_matches!(homing_scoop, Type::Homing(Some(Homing::Scoop)));
assert_matches!(homing_bar, Type::Homing(Some(Homing::Bar)));
assert_matches!(homing_bump, Type::Homing(Some(Homing::Bump)));
}

#[test]
fn kle_from_json() {
let result1: Vec<_> = from_json(&unindent(
Expand Down
Loading

0 comments on commit b732336

Please sign in to comment.