generated from ElnuDev/rust-project
Import from KLE
This commit is contained in:
parent
31572568da
commit
79813a2549
9 changed files with 194 additions and 189 deletions
|
@ -6,7 +6,9 @@ edition = "2021"
|
|||
[dependencies]
|
||||
askama = "0.12.0"
|
||||
derive_more = "0.99.17"
|
||||
kle-serial = "0.2.2"
|
||||
lazy_static = "1.4.0"
|
||||
regex = "1.9.3"
|
||||
serde_json = "1.0.105"
|
||||
strum = "0.25.0"
|
||||
strum_macros = "0.25.2"
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
mod oyayubi;
|
||||
pub use oyayubi::OYAYUBI;
|
||||
|
||||
use std::fmt::{Display, self};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Key<'a> {
|
||||
Oyayubi {
|
||||
latin: char,
|
||||
normal: char,
|
||||
shift: char,
|
||||
alt_shift: Option<char>,
|
||||
},
|
||||
Single {
|
||||
text: &'a str,
|
||||
u: f64,
|
||||
},
|
||||
Icon {
|
||||
icon_path: &'a str,
|
||||
u: f64,
|
||||
},
|
||||
Break,
|
||||
}
|
||||
|
||||
pub const fn oyayubi<'a>(latin: char, normal: char, shift: char, alt_shift: Option<char>) -> Key<'a> {
|
||||
Key::Oyayubi {
|
||||
latin,
|
||||
normal,
|
||||
shift,
|
||||
alt_shift,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn single<'a>(text: &'a str, u: f64) -> Key<'a> {
|
||||
Key::Single {
|
||||
text,
|
||||
u,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn icon<'a>(icon_path: &'a str, u: f64) -> Key<'a> {
|
||||
Key::Icon {
|
||||
icon_path,
|
||||
u,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Key<'a> {
|
||||
pub fn width_mod(&self) -> f64 {
|
||||
use Key::*;
|
||||
match self {
|
||||
Oyayubi { .. } => 1.0,
|
||||
Single { u, .. } => *u,
|
||||
Icon { u, .. } => *u,
|
||||
Break => 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Display for Key<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use Key::*;
|
||||
write!(f, "{}", match self {
|
||||
Oyayubi { latin, .. } => latin.to_string(),
|
||||
Single { text, .. } => text.to_string(),
|
||||
Icon { icon_path, .. } => icon_path.to_string(),
|
||||
Break => "".to_string(),
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
use super::Key;
|
||||
use super::oyayubi as k;
|
||||
|
||||
pub const OYAYUBI: [Key; 30] = [
|
||||
k('Q', '。', 'ぁ', None),
|
||||
k('W', 'か', 'え', None),
|
||||
k('E', 'た', 'り', None),
|
||||
k('R', 'こ', 'ゃ', None),
|
||||
k('T', 'さ', 'れ', None),
|
||||
k('Y', 'ら', 'よ', Some('ぱ')),
|
||||
k('U', 'ち', 'に', None),
|
||||
k('I', 'く', 'る', None),
|
||||
k('O', 'つ', 'ま', None),
|
||||
k('P', ',', 'ぇ', Some('ぴ')),
|
||||
k('A', 'う', 'を', None),
|
||||
k('S', 'し', 'あ', None),
|
||||
k('D', 'て', 'な', None),
|
||||
k('F', 'け', 'ゅ', None),
|
||||
k('G', 'せ', 'も', None),
|
||||
k('H', 'は', 'み', None),
|
||||
k('J', 'と', 'お', None),
|
||||
k('K', 'き', 'の', None),
|
||||
k('L', 'い', 'ょ', Some('ぽ')),
|
||||
k(';', 'ん', 'っ', None), // Missing +
|
||||
k('Z', '.', 'ぅ', None),
|
||||
k('X', 'ひ', 'ー', None),
|
||||
k('C', 'す', 'ろ', None),
|
||||
k('V', 'ふ', 'や', None),
|
||||
k('B', 'へ', 'ぃ', None),
|
||||
k('N', 'め', 'ぬ', Some('ぷ')),
|
||||
k('M', 'そ', 'ゆ', None),
|
||||
k(',', 'ね', 'む', Some('ぺ')), // Missing <
|
||||
k('.', 'ほ', 'わ', None), // Missing >
|
||||
k('?', '・', 'ぉ', Some('ゎ')) // Missing /
|
||||
];
|
|
@ -1,9 +1,6 @@
|
|||
pub mod svg;
|
||||
use svg::*;
|
||||
|
||||
pub mod key;
|
||||
use key::*;
|
||||
|
||||
use askama::Template;
|
||||
use derive_more::From;
|
||||
use std::{fs::OpenOptions, io::Write};
|
||||
|
@ -13,46 +10,32 @@ use lazy_static::lazy_static;
|
|||
#[template(path = "document.xml")]
|
||||
struct DocumentTemplate<'a> {
|
||||
dimensions: &'a DocumentDimensions,
|
||||
box_size: SVGMeasure,
|
||||
positions: Vec<(&'a Key<'a>, (SVGMeasure, SVGMeasure))>,
|
||||
keyboard: kle_serial::Keyboard,
|
||||
}
|
||||
|
||||
struct DocumentDimensions {
|
||||
width: SVGMeasure,
|
||||
height: SVGMeasure,
|
||||
margin: SVGMeasure,
|
||||
}
|
||||
|
||||
fn kle_font_units(kle_font_units: &usize) -> SVGMeasure {
|
||||
return SVGMeasure::new((6 + kle_font_units * 2) as f64, SVGUnit::Pixel);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref LETTER_LANDSCAPE: DocumentDimensions = DocumentDimensions {
|
||||
width: SVGMeasure::new(11.0, SVGUnit::Inch),
|
||||
height: SVGMeasure::new(8.5, SVGUnit::Inch),
|
||||
margin: SVGMeasure::new(0.25, SVGUnit::Inch),
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(From, Debug)]
|
||||
enum Error {
|
||||
Io(std::io::Error),
|
||||
Template(askama::Error),
|
||||
}
|
||||
|
||||
fn positions<'a>(
|
||||
keys: &'a Vec<Key>,
|
||||
size: SVGMeasure,
|
||||
margin: SVGMeasure,
|
||||
padding: SVGMeasure,
|
||||
dimensions: &DocumentDimensions,
|
||||
) -> Vec<(&'a Key<'a>, (SVGMeasure, SVGMeasure))> {
|
||||
let grid = size + padding;
|
||||
let mut x = margin;
|
||||
let mut y = margin;
|
||||
let mut positions = Vec::with_capacity(keys.len());
|
||||
for key in keys {
|
||||
if let Key::Break = key {
|
||||
x = margin;
|
||||
y = y + grid;
|
||||
continue;
|
||||
}
|
||||
if x + grid > dimensions.width - margin {
|
||||
x = margin;
|
||||
y = y + grid;
|
||||
}
|
||||
positions.push((key, (x, y)));
|
||||
x = x + size * key.width_mod() + padding;
|
||||
}
|
||||
positions
|
||||
LayoutParse(serde_json::Error),
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
|
@ -61,33 +44,10 @@ fn main() -> Result<(), Error> {
|
|||
.truncate(true)
|
||||
.create(true)
|
||||
.open("output.svg")?;
|
||||
let dimensions = DocumentDimensions {
|
||||
width: SVGMeasure::new(8.5, SVGUnit::Inch),
|
||||
height: SVGMeasure::new(11.0, SVGUnit::Inch),
|
||||
};
|
||||
let box_size = SVGMeasure::new(14.0, SVGUnit::Millimeter);
|
||||
let padding = SVGMeasure::new(2.5, SVGUnit::Millimeter);
|
||||
let margin = SVGMeasure::new(0.25, SVGUnit::Inch);
|
||||
let document = DocumentTemplate {
|
||||
positions: positions(&KEYS, box_size, margin, padding, &dimensions),
|
||||
dimensions: &dimensions,
|
||||
box_size,
|
||||
dimensions: &LETTER_LANDSCAPE,
|
||||
keyboard: serde_json::from_str(&std::fs::read_to_string("layout.json")?)?,
|
||||
};
|
||||
write!(file, "{}", document.render()?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref KEYS: Vec<Key<'static>> = {
|
||||
let mut keys = OYAYUBI.to_vec();
|
||||
keys.push(Key::Break);
|
||||
keys.push(single("親指左", 3.0));
|
||||
keys.push(single("親指右", 3.0));
|
||||
keys.push(Key::Break);
|
||||
keys.push(icon("assets/nixos.svg", 1.0));
|
||||
keys.push(icon("assets/playpause.svg", 1.0));
|
||||
keys.push(icon("assets/previous.svg", 1.0));
|
||||
keys.push(icon("assets/next.svg", 1.0));
|
||||
keys
|
||||
};
|
||||
}
|
|
@ -19,7 +19,7 @@ pub struct SVGMeasure {
|
|||
}
|
||||
|
||||
impl SVGMeasure {
|
||||
pub fn new(measure: f64, unit: SVGUnit) -> Self {
|
||||
pub const fn new(measure: f64, unit: SVGUnit) -> Self {
|
||||
Self { measure, unit }
|
||||
}
|
||||
|
||||
|
|
|
@ -4,30 +4,63 @@
|
|||
<defs>
|
||||
<style type="text/css"><![CDATA[@import url('https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c:wght@700&display=swap');]]></style>
|
||||
</defs>
|
||||
{% for (key, (x, y)) in positions %}
|
||||
{% let width = box_size * key.width_mod() %}
|
||||
<g x="{{ x }}" y="{{ y }}" transform="translate({{ x.to_user_units() }},{{ y.to_user_units() }})" width="{{ width }}" height="{{ box_size }}">
|
||||
<rect width="{{ width }}" height="{{ box_size }}" fill="none" stroke="#cccccc" stroke-width="1pt" rx="2mm" />
|
||||
{% let dy = "0.125em" %}
|
||||
{% match key %}
|
||||
{% when crate::key::Key::Oyayubi with { latin, normal, shift, alt_shift } %}
|
||||
{% let font_size = "0.45cm" %}
|
||||
{% let latin_font_size = "0.4cm" %}
|
||||
{% let alt_shift_font_size = "0.325cm" %}
|
||||
<text x="{{ width * 0.25 }}" y="{{ box_size * 0.25 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ latin_font_size }}" dy="{{ dy }}">{{ latin }}</text>
|
||||
<text x="{{ width * 0.75 }}" y="{{ box_size * 0.25 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ font_size }}" dy="{{ dy }}">{{ shift }}</text>
|
||||
<text x="{{ width * 0.75 }}" y="{{ box_size * 0.75 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ font_size }}" dy="{{ dy }}">{{ normal }}</text>
|
||||
{% if let Some(alt_shift) = alt_shift %}
|
||||
<text x="{{ width / 2.0 }}" y="{{ box_size / 2.0 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ alt_shift_font_size }}" dy="{{ dy }}">{{ alt_shift }}</text>
|
||||
{% endif %}
|
||||
{% when crate::key::Key::Single with { text, u } %}
|
||||
{% let font_size = "0.5cm" %}
|
||||
<text x="{{ width * 0.5 }}" y="{{ box_size * 0.5 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ font_size }}" dy="{{ dy }}">{{ text }}</text>
|
||||
{% when crate::key::Key::Icon with { icon_path, u } %}
|
||||
{% let icon_width_mm = 7.5 %}
|
||||
<image x="{{ width.measure * 0.5 - icon_width_mm * 0.5 }}mm" y="{{ box_size.measure * 0.5 - icon_width_mm * 0.5 }}mm" href="{{ icon_path }}" width="{{ icon_width_mm }}mm" height="{{ icon_width_mm }}mm" />
|
||||
{% when crate::key::Key::Break %}
|
||||
{% endmatch %}
|
||||
{% let u = crate::svg::SVGMeasure::new(14.0, crate::svg::SVGUnit::Millimeter) %}
|
||||
{% let padding = crate::svg::SVGMeasure::new(2.5, crate::svg::SVGUnit::Millimeter) %}
|
||||
{% let dy = "0.125em" %}
|
||||
{% for key in keyboard.keys %}
|
||||
{% let x = u * key.x + padding * key.x + dimensions.margin %}
|
||||
{% let y = u * key.y + padding * key.y + dimensions.margin %}
|
||||
{% let width = u * key.width %}
|
||||
{% let height = u * key.height %}
|
||||
<g x="{{ x }}" y="{{ y }}" transform="translate({{ x.to_user_units() }},{{ y.to_user_units() }})" width="{{ width }}" height="{{ height }}">
|
||||
<rect width="{{ width }}" height="{{ height }}" fill="none" stroke="#cccccc" stroke-width="1pt" rx="2mm" />
|
||||
|
||||
{# top-left #}
|
||||
{% if let Some(legend) = key.legends[0] %}
|
||||
<text x="{{ width * 0.25 }}" y="{{ height * 0.25 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ crate::kle_font_units(legend.size) }}" dy="{{ dy }}">{{ legend.text }}</text>
|
||||
{% endif %}
|
||||
|
||||
{# top-center #}
|
||||
{% if let Some(legend) = key.legends[1] %}
|
||||
<text x="{{ width * 0.5 }}" y="{{ height * 0.25 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ crate::kle_font_units(legend.size) }}" dy="{{ dy }}">{{ legend.text }}</text>
|
||||
{% endif %}
|
||||
|
||||
{# top-right #}
|
||||
{% if let Some(legend) = key.legends[2] %}
|
||||
<text x="{{ width * 0.75 }}" y="{{ height * 0.25 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ crate::kle_font_units(legend.size) }}" dy="{{ dy }}">{{ legend.text }}</text>
|
||||
{% endif %}
|
||||
|
||||
{# middle-left #}
|
||||
{% if let Some(legend) = key.legends[3] %}
|
||||
<text x="{{ width * 0.25 }}" y="{{ height * 0.5 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ crate::kle_font_units(legend.size) }}" dy="{{ dy }}">{{ legend.text }}</text>
|
||||
{% endif %}
|
||||
|
||||
{# middle-center #}
|
||||
{% if let Some(legend) = key.legends[4] %}
|
||||
<text x="{{ width * 0.5 }}" y="{{ height * 0.5 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ crate::kle_font_units(legend.size) }}" dy="{{ dy }}">{{ legend.text }}</text>
|
||||
{% endif %}
|
||||
|
||||
{# middle-right #}
|
||||
{% if let Some(legend) = key.legends[5] %}
|
||||
<text x="{{ width * 0.75 }}" y="{{ height * 0.5 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ crate::kle_font_units(legend.size) }}" dy="{{ dy }}">{{ legend.text }}</text>
|
||||
{% endif %}
|
||||
|
||||
{# bottom-left #}
|
||||
{% if let Some(legend) = key.legends[6] %}
|
||||
<text x="{{ width * 0.25 }}" y="{{ height * 0.75 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ crate::kle_font_units(legend.size) }}" dy="{{ dy }}">{{ legend.text }}</text>
|
||||
{% endif %}
|
||||
|
||||
{# bottom-center #}
|
||||
{% if let Some(legend) = key.legends[7] %}
|
||||
<text x="{{ width * 0.55 }}" y="{{ height * 0.75 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ crate::kle_font_units(legend.size) }}" dy="{{ dy }}">{{ legend.text }}</text>
|
||||
{% endif %}
|
||||
|
||||
{# bottom-right #}
|
||||
{% if let Some(legend) = key.legends[8] %}
|
||||
<text x="{{ width * 0.75 }}" y="{{ height * 0.75 }}" dominant-baseline="middle" text-anchor="middle" style="font-family: 'M PLUS Rounded 1c'" font-size="{{ crate::kle_font_units(legend.size) }}" dy="{{ dy }}">{{ legend.text }}</text>
|
||||
{% endif %}
|
||||
|
||||
{# TODO 9-11 are side #}
|
||||
</g>
|
||||
{% endfor %}
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 4 KiB |
Loading…
Add table
Add a link
Reference in a new issue