Merge pull request 'Eleminiere Abhängigkeit von perl und php.' (#604) from htgoebel/neo-layout:master into master

Reviewed-on: #604
This commit is contained in:
hrnz 2022-02-11 01:33:00 +01:00
commit 2f8c93f1e4
8 changed files with 482 additions and 3742 deletions

View File

@ -21,9 +21,7 @@ Um alle Bilder erzeugen können, benötigt man eine Vielzahl an Abhängigkeiten:
- sed
- ed
- libxkbcommon (xkbcli)
- python mit jinja2, more-itertools, numpy, pandas, matplotlib und seaborn
- perl mit XML::Writer
- php
- python mit jinja2, numpy, pandas, matplotlib, seaborn und lxml
- Linux Libertine
- Gentium Plus Compact
- DejaVu Sans Mono

View File

@ -1,7 +1,7 @@
all: default
%-grau-1234.svg: ../../A-REFERENZ-A/%.txt
./alle-grau-1234.pl $< > $@
./alle-grau-1234.py $< > $@
EXTRASVG=\
neo20-grau-1234.svg \

View File

@ -1,256 +0,0 @@
#!/usr/bin/env -S perl -w
use strict;
use warnings;
use XML::Writer;
use open ':encoding(utf8)';
use utf8;
sub start_svg;
sub end_svg;
sub create_defs;
sub create_key;
sub parse_ref;
sub in2px;
sub create_keys;
sub round;
my $dpi = 90;
# a4 paper
my $height = in2px(8.268);
my $width = in2px(11.69);
my $keywidth = in2px(0.75);
my $keyheight = in2px(0.75);
my $labelwidth = in2px(0.5);
my $labelheight = in2px(0.55);
my $posx = 0;
my $posy = 0;
my $row = 0;
my %kp_mapping = ( # mapping for keypad, level 4
'Hom' => '⇱',
'KP↑' => '⇡',
'PgU' => '⇞',
'KP←' => '⇠',
'Beg' => '•',
'KP→' => '⇢',
'End' => '⇲',
'KP↓' => '⇣',
'PgD' => '⇟',
'Ins' => '⎀',
'Del' => '⌦',
'Ent' => '⏎',
'vec' => ' ⃗'
);
my $writer = new XML::Writer(ENCODING => 'utf-8',
DATA_MODE => 1,
DATA_INDENT => 2);
start_svg;
create_defs;
create_keys(parse_ref);
end_svg;
exit;
# parse reference and return multi-array
sub parse_ref {
my @letters;
open REF, $ARGV[0]
or die 'Error opening reference: '.$!;
while (<REF>) {
my @layer;
last if /^== Zeichenerläuterungen/;
# layout blocks
if(/Miniatur ===$/) {
while(<REF>) {
last if(/^$/); # empty line => end of current block
next if($_ !~ /^│/); # skip horizontal dividers
push @layer, split /│/;
}
push @letters, [ @layer ]; # push ref
}
}
close REF;
return @letters;
}
sub create_keys {
my @letters = @_;
for (0..$#{$letters[0]}) { # letters
create_key
$letters[0][$_],
$letters[0][$_],
$letters[1][$_],
$letters[2][$_],
$letters[3][$_];
}
for (0..$#{$letters[7]}) { # numbers
create_key
$letters[7][$_],
$letters[7][$_],
$letters[8][$_],
$letters[9][$_],
$letters[10][$_];
}
}
sub in2px {
return ($_[0]||0) * $dpi;
}
sub start_svg {
$writer->xmlDecl('UTF-8');
$writer->doctype('svg', '-//W3C//DTD SVG 20001102//EN',
'http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd');
$writer->startTag('svg', height => $height, width => $width,
'xmlns' => 'http://www.w3.org/2000/svg',
'xmlns:xlink' => 'http://www.w3.org/1999/xlink');
}
sub end_svg {
$writer->endTag('svg');
$writer->end();
}
# create the key template
sub create_defs {
$writer->startTag('defs');
# style information
$writer->dataElement('style', '
text.common {
font-family:Linux Biolinum O, Linux Biolinum;
font-style:normal;
font-variant:normal;
font-stretch:normal;
text-align:center;
text-anchor:middle;
stroke:none;
}
text.main {
/*font-weight:bold;*/
font-size:19px;
fill:#eeeeee;
stroke-width:4;
}
text.special {
font-size:16px;
stroke-width:3;
}
text.outline {
stroke:#111111;
stroke-linejoin:round;
}
rect#boundary {
fill:none;
stroke:#eeeeee;
stroke-width:'.in2px(0.005).';
}
rect#border {
fill:#333333;
stroke:#eeeeee;
stroke-width:'.in2px(0.025).';
}
text.level1 {
}
text.level2 {
}
text.level3 {
fill:#99dd66;
}
text.level4 {
fill:#6699dd;
font-size:13px;
}', type => 'text/css');
# boundary of keys
$writer->emptyTag('rect',
id => 'boundary',
width => $keywidth, height => $keyheight,
rx => 5);
# border for keys, actual key stickers
$writer->emptyTag('rect',
id => 'border',
width => $labelwidth, height => $labelheight,
rx => 10);
$writer->endTag('defs');
}
# create a specific key (cloned from template)
# first parameter (0) is first level, and is only used for line breaks in the graphic
# param 1..4 are actual layers
sub create_key {
my @keys = @_;
$keys[0] = '' unless defined($keys[0]);
$keys[1] = '' unless defined($keys[1]);
s/\s//g for @keys; # remove any space
# map words to symbols for numblock
foreach (keys %kp_mapping) {
$keys[3] =~ s/\Q$_/\Q$kp_mapping{$_}/;
$keys[4] =~ s/\Q$_/\Q$kp_mapping{$_}/;
}
return if length($keys[0]) != 1;
$writer->startTag('g',
transform => "translate($posx,$posy)",
id => 'key_'.(join '', @keys));
$writer->emptyTag('use', 'xlink:href' => '#boundary');
$writer->startTag('g',
transform => 'translate('.(($keywidth-$labelwidth)/2.5).', 2)');
$writer->emptyTag('use', 'xlink:href' => '#border');
# add text+outlines to sticker
for(' outline', '') {
$writer->dataElement('text', $keys[1],
transform => 'translate(15,41)',
class => "level1 common main$_")
# do not show e1, if it's the same letter as e2
# only use for latin letters
unless(#$keys[1] =~ /[a-züöäß]/ &&
$keys[1] =~ /\Q$keys[2]/i);
$writer->dataElement('text', $keys[2]||'',
transform => 'translate(15,19)',
class => "level2 common main$_");
$writer->dataElement('text', $keys[3]||'',
transform => 'translate(32,18)',
class => "level3 common special$_");
$writer->dataElement('text', $keys[4]||'',
transform => 'translate(32,42)',
class => "level4 common special$_");
# do not show e4 on keypad
#unless($row > 4 && $keys[0] =~ /\d/i);
}
$writer->endTag('g');
$writer->endTag('g');
$posx += $keywidth;
if($row < 3) {
if($keys[0] =~ /[`´y]/) { # split keyboard rows, dirty way
$posx = ++$row*$keywidth/2; # not really accurate, but works
$posy += $keyheight;
}
} elsif($keys[0] =~ /[-93+j]/) { # keypad
$posx = ++$row*0;
$posy += $keyheight;
}
}
sub round {
return int($_[0]+.5*($_[0]<=>0));
}

View File

@ -0,0 +1,221 @@
#!/usr/bin/env python
import sys
from lxml import etree as ET
def in2px(inch):
return round(inch * DPI, 2)
DPI = 90
# a4 paper
HEIGHT = in2px(8.268)
WIDTH = in2px(11.69)
KEYWIDTH = in2px(0.75)
KEYHEIGHT = in2px(0.75)
LABELWIDTH = in2px(0.5)
LABELHEIGHT = in2px(0.55)
KP_MAPPING = { # mapping for keypad, level 4
'Hom': '',
'KP↑': '',
'PgU': '',
'KP←': '',
'Beg': '',
'KP→': '',
'End': '',
'KP↓': '',
'PgD': '',
'Ins': '',
'Del': '',
'Ent': '',
'vec': ' ⃗'
}
strokewidth = in2px(0.005)
STYLESHEET = '''
text.common {
font-family:Linux Biolinum O, Linux Biolinum;
font-style:normal;
font-variant:normal;
font-stretch:normal;
text-align:center;
text-anchor:middle;
stroke:none;
}
text.main {
/*font-weight:bold;*/
font-size:19px;
fill:#eeeeee;
stroke-width:4;
}
text.special {
font-size:16px;
stroke-width:3;
}
text.outline {
stroke:#111111;
stroke-linejoin:round;
}
rect#boundary {
fill:none;
stroke:#eeeeee;
stroke-width:''' + str(in2px(0.005)) + '''px;
}
rect#border {
fill:#333333;
stroke:#eeeeee;
stroke-width:''' + str(in2px(0.025)) + '''px;
}
text.level1 {
}
text.level2 {
}
text.level3 {
fill:#99dd66;
}
text.level4 {
fill:#6699dd;
font-size:13px;
}'''
NSMAP = {None: 'http://www.w3.org/2000/svg',
'xlink': 'http://www.w3.org/1999/xlink'}
XLINK = '{%s}' % NSMAP['xlink']
DOCTYPE = ('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN" '
'"http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">')
def parse_ref(filename):
'''parse reference and return multi-array'''
with open(filename) as fh:
lines = fh.read().splitlines()
keymap = []
state = 0
for line in lines:
line = line.strip()
if state == 0:
if line.endswith("Miniatur ==="):
state = 1
layer = []
keymap.append(layer)
continue
elif not line: # empty line: end of current block/layer
state = 0
layer = None
continue
elif not line.startswith(""): # skip horizontal dividers
continue
else:
line = [k.strip() for k in line.split("")]
layer.append(line[1:-1])
return keymap
def create_defs(parent):
'''create the key template'''
node = ET.SubElement(parent, 'defs')
# style sheet
ET.SubElement(node, 'style', type='text/css').text = STYLESHEET
# boundary of keys
ET.SubElement(node, 'rect', id='boundary',
width=str(KEYWIDTH), height=str(KEYHEIGHT), rx="5")
# border for keys, actual key stickers
ET.SubElement(node, 'rect', id='border',
width=str(LABELWIDTH), height=str(LABELHEIGHT), rx="10")
def create_keys(parent, keymap):
posy = 0
# main keyboard
# TODO remove leading blank key
for row in range(len(keymap[0])):
posx = row / 2 * KEYWIDTH # not really accurate, but works
for key in range(len(keymap[0][row])):
key = create_key(parent, posx, posy,
keymap[0][row][key],
keymap[1][row][key],
keymap[2][row][key],
keymap[3][row][key])
if key is not None: # advance only if sticker was output
posx += KEYWIDTH
posy += KEYHEIGHT
# numpad
for row in range(len(keymap[7])):
posx = 0
for key in range(len(keymap[7][row])):
key = create_key(parent, posx, posy,
keymap[7][row][key],
keymap[8][row][key],
keymap[9][row][key],
keymap[10][row][key])
if key is not None: # advance only if sticker was output
posx += KEYWIDTH
posy += KEYHEIGHT
def create_key(parent, posx, posy, *keys):
'''create a specific key (cloned from template)'''
if len(keys[0]) != 1: # skip keys like Tab at the left side
return
def text(level, trans, type):
ET.SubElement(
g1, 'text',
{'transform': f'translate({trans})',
'class': f"level{level} common {type}{outline}"}
).text = keys[level-1]
keys = list(keys)
# map words to symbols for numblock
keys[2] = KP_MAPPING.get(keys[2], keys[2])
keys[3] = KP_MAPPING.get(keys[3], keys[3])
g0 = ET.SubElement(parent, 'g',
transform=f"translate({posx},{posy})",
id='key_' + ''.join(keys))
ET.SubElement(g0, 'use', {XLINK + 'href': '#boundary'})
g1 = ET.SubElement(g0, 'g',
transform=f'translate({(KEYWIDTH-LABELWIDTH)/2.5}, 2)')
ET.SubElement(g1, 'use', {XLINK + 'href': '#border'})
# do not show e1, if it's the same letter as e2
upper_eq_lower = (keys[1].lower() == keys[0])
# add text+outlines to sticker
for outline in (' outline', ''):
if not upper_eq_lower:
text(1, '15,41', 'main')
text(2, '15,19', 'main')
text(3, '32,18', 'special')
text(4, '32,42', 'special')
return g0
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('filename')
args = parser.parse_args()
keymap = parse_ref(args.filename)
root = ET.Element('svg',
height=str(HEIGHT), width=str(WIDTH),
nsmap=NSMAP)
create_defs(root)
create_keys(root, keymap)
doc = ET.tostring(root, encoding="UTF-8", xml_declaration=True,
doctype=DOCTYPE, pretty_print=True)
sys.stdout.buffer.write(doc)
main()

View File

@ -7,13 +7,13 @@ neo-bunt-123456.png: neo-bunt-123456.ods
libreoffice --convert-to png $<
neo20-grau-123456.svg:
./all-grau-123456.php neo20
./all-grau-123456.py neo20
bone-grau-123456.svg:
./all-grau-123456.php bone
./all-grau-123456.py bone
neoqwertz-grau-123456.svg:
./all-grau-123456.php neoqwertz
./all-grau-123456.py neoqwertz
EXTRASVG=\
neo20-grau-123456.svg \

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,255 @@
#!/usr/bin/env python
import os
from lxml import etree as ET
REFERENZ_DIR = '../../A-REFERENZ-A/'
KEYWIDTH = KEYHEIGHT = 72
LABELWIDTH = KEYWIDTH
LABELHEIGHT = KEYWIDTH
KP_MAPPING = { # mapping for keypad, level 4
'Hom': '',
'KP↑': '',
'PgU': '',
'KP←': '',
'Beg': '',
'KP→': '',
'End': '',
'KP↓': '',
'PgD': '',
'Ins': '',
'Del': '',
'Ent': '',
'vec': ' ⃗'
}
STYLESHEET = '''
rect.grey { fill:#cccccc !important }
rect.key { fill:white; stroke:black; stroke-width: 1 }
text {
/* font-family:Linux Biolinum O, Linux Biolinum;*/
font-family:normal;
font-style:normal;
font-variant:normal;
font-stretch:normal;
stroke:none;
text-align:center;
text-anchor:middle;
dominant-baseline: middle;
fill: black;
}
text.main { font-weight:bold }
text.special { }
text.level1 { font-size:22px }
text.level2 { font-size:22px }
text.level3 { font-size:14px }
text.level4 { font-size:14px }
text.level5 { font-size:14px }
text.level6 { font-size:14px }
text.deadkey { fill: red }
text.modifier { font-size:20px }
'''
NSMAP = {None: 'http://www.w3.org/2000/svg',
'xlink': 'http://www.w3.org/1999/xlink'}
XLINK = '{%s}' % NSMAP['xlink']
DOCTYPE = ('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN" '
'"http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">')
LAYOUT = (
[1] * 13 + [2.0],
[1.5] + [1] * 12 + [0],
[1.75] + [1] * 11 + [1.0, 0],
[1.25, 1.0] + [1] * 10 + [2.75, 0],
)
SPECIAL_KEYS = (
(0, 13, 2.0, "Backspace"),
(1, 0, 1.5, "Tab"),
(2, 0, 1.75, "Mod 3"),
(2, 12.75, 1, "Mod 3"),
(3, 0, 1.25, "Umsch"),
(3, 1.25, 1, "Mod 4"),
(3, 12.25, 2.75, "Umschalt"),
(4, 0, 1.5, "Strg"),
(4, 2.5, 1.5, "Alt"),
(4, 9.5, 1.5, "Mod4"),
(4, 13.5, 1.5, "Strg"),
)
def parse_ref(layout):
'''parse reference and return multi-array'''
filename = os.path.join(REFERENZ_DIR, f'{layout}.txt')
with open(filename) as fh:
lines = fh.read().splitlines()
keymap = []
state = 0
for line in lines:
line = line.strip()
if state == 0:
if line.endswith("Miniatur ==="):
state = 1
layer = []
keymap.append(layer)
continue
elif not line: # empty line: end of current block/layer
state = 0
layer = None
continue
elif not line.startswith(""): # skip horizontal dividers
continue
else:
line = [k.strip() for k in line.split("")]
layer.append(line[1:-1])
return keymap
def create_defs(parent):
'''create the key template'''
node = ET.SubElement(parent, 'defs')
# style sheet
ET.SubElement(node, 'style', type='text/css').text = STYLESHEET
# boundary of keys
# ET.SubElement(node, 'rect', id='boundary',
# width=str(KEYWIDTH), height=str(KEYHEIGHT), rx="0")
# # border for keys, actual key stickers
# ET.SubElement(node, 'rect', id='border',
# width=str(LABELWIDTH), height=str(LABELHEIGHT), rx="0")
def draw_keys(parent):
# draw return key first to be overdrawn by others
w = sum(LAYOUT[0]) * KEYWIDTH
posx = sum(LAYOUT[1]) * KEYWIDTH
ET.SubElement(parent, 'rect', {'class': 'key grey'},
x=str(posx), y=str(KEYHEIGHT + 1),
width=str(w - posx), height=str(2 * KEYHEIGHT))
def rect(x, y, kwidth, classes):
kwidth *= KEYWIDTH
ET.SubElement(parent, 'rect', {'class': classes},
x=str(x), y=str(y),
width=str(kwidth), height=str(KEYHEIGHT))
return kwidth
# other keys
posy = 1
for row in LAYOUT:
posx = 0
for key in row:
if not key:
continue
elif isinstance(key, float):
kwidth = key * KEYWIDTH
else:
kwidth = rect(posx, posy, key, 'key')
posx += kwidth
posy += KEYHEIGHT
drawing_width = posx + 1
# special keys
for row, col_offset, kwidth, label in SPECIAL_KEYS:
rect(col_offset * KEYWIDTH, row * KEYHEIGHT + 1, kwidth, 'key grey')
rect(4 * KEYWIDTH, posy, 5.5, 'key') # Leertaste
posy += KEYHEIGHT
return drawing_width, posy
def create_labels(parent, keymap):
posy = 1
# main keyboard
for row in range(len(keymap[0])-1):
posx = 0
for key in range(len(keymap[0][row])):
create_label(parent, posx, posy,
keymap[0][row][key],
keymap[1][row][key],
keymap[2][row][key],
keymap[3][row][key],
keymap[4][row][key],
keymap[5][row][key])
posx += LAYOUT[row][key] * KEYWIDTH
posy += KEYHEIGHT
def text(x, y, kwidth, label):
x = x * KEYWIDTH + kwidth * KEYWIDTH / 2 + 1
y = y * KEYHEIGHT + KEYHEIGHT / 2 + 1
ET.SubElement(
parent, 'text',
{'x': str(x), 'y': str(y),
'class': 'modifier'}
).text = label
# special keys
for row, col_offset, kwidth, label in SPECIAL_KEYS:
text(col_offset, row, kwidth, label)
text(13.5, 1.25, 1.75, "Return")
def create_label(parent, posx, posy, *labels):
'''create a specific key (cloned from template)'''
def text(level, trans, type):
ET.SubElement(
g, 'text',
{'transform': f'translate({trans})',
'class': f"level{level} {type} {deadkey}"}
).text = labels[level-1]
labels = list(labels)
if len(labels[0]) > 1:
# special keys are labels special above
return
# map words to symbols for numblock
labels[2] = KP_MAPPING.get(labels[2], labels[2])
labels[3] = KP_MAPPING.get(labels[3], labels[3])
g = ET.SubElement(parent, 'g',
transform=f"translate({posx},{posy})",
id='key_' + ''.join(labels))
upper_eq_lower = (labels[1].lower() == labels[0])
deadkey = 'deadkey' if labels[0] in "ˆ`´" else 'live'
if upper_eq_lower:
# do not show e1, if it's the same letter as e2
text(2, '15,35', 'main')
else:
text(1, '15,55', 'main')
text(2, '15,20', '')
text(3, '42,50', 'special')
text(4, '42,20', 'special')
text(5, '59,50', 'special')
text(6, '59,20', 'special')
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('layout')
args = parser.parse_args()
keymap = parse_ref(args.layout)
root = ET.Element('svg',
nsmap=NSMAP)
create_defs(root)
width, height = draw_keys(root)
create_labels(root, keymap)
root.set('width', str(width))
root.set('height', str(height))
doc = ET.tostring(root, encoding="utf-8", xml_declaration=True,
doctype=DOCTYPE, pretty_print=True)
with open(f'{args.layout}-grau-123456.svg', 'wb') as fh:
fh.write(doc)
main()

View File

@ -14,9 +14,7 @@ pkgs.mkShell {
python3Packages.seaborn
python3Packages.more-itertools
python3Packages.jinja2
perl
perlPackages.XMLWriter
php
python3Packages.lxml
];
# You also need to install the fonts (libertine gentium dejavu ... )