mirror of
https://bjh21.me.uk/bedstead/.git
synced 2026-07-09 13:33:06 -04:00
277 lines
10 KiB
HTML
277 lines
10 KiB
HTML
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-GB" xml:lang="en-GB">
|
|
<head>
|
|
<!-- SPDX-License-Identifier: CC0-1.0 -->
|
|
<link rel="stylesheet" href="bedstead.css" type="text/css" />
|
|
<title>Bedstead Editor</title>
|
|
<link rel="icon" href="icon-16.png" type="image/png" sizes="16x16" />
|
|
<link rel="icon" href="icon-32.png" type="image/png" sizes="32x32" />
|
|
<link rel="icon" href="icon-64.png" type="image/png" sizes="64x64" />
|
|
<style>
|
|
:root {
|
|
--pix: 7vmin;
|
|
}
|
|
body {
|
|
max-width: none;
|
|
}
|
|
#inout {
|
|
display: flex;
|
|
}
|
|
#inpane, #outpane {
|
|
padding-left: var(--pix);
|
|
padding-top: var(--pix);
|
|
width: calc(5 * var(--pix));
|
|
height: calc(9 * var(--pix));
|
|
}
|
|
#pixels {
|
|
border-spacing: 0;
|
|
}
|
|
#pixels td {
|
|
padding: 0;
|
|
line-height: 0;
|
|
}
|
|
#pixels input {
|
|
appearance: none;
|
|
color: inherit;
|
|
margin: 0;
|
|
width: var(--pix);
|
|
height: var(--pix);
|
|
border: 1px solid;
|
|
}
|
|
#pixels input:active {
|
|
border: 3px solid;
|
|
}
|
|
#pixels input:checked {
|
|
background: currentColor;
|
|
}
|
|
#pixels input:checked:active {
|
|
border: 0;
|
|
margin: 3px;
|
|
width: calc(var(--pix) - 6px);
|
|
height: calc(var(--pix) - 6px);
|
|
}
|
|
#pixels input:focus-visible {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
</style>
|
|
<!-- Script is async rather than deferred because Chromium can't
|
|
handle deferred scripts in XHTML.
|
|
https://issues.chromium.org/issues/40518469
|
|
And it's not a module because Safari can't handle that. -->
|
|
<script async="async"><![CDATA[
|
|
"use strict";
|
|
var Bedstead;
|
|
function update_glyph(c_update_needed) {
|
|
var args = [];
|
|
var cstr = "";
|
|
for (var row of document.querySelector('#pixels').rows) {
|
|
var arg = 0;
|
|
for (var pixel of row.querySelectorAll('input')) {
|
|
arg *= 2;
|
|
if (pixel.checked) arg += 1
|
|
}
|
|
args.push(arg.toString());
|
|
cstr += "\\" + arg.toString(8).padStart(2, "0");
|
|
}
|
|
if (c_update_needed)
|
|
document.getElementById("c").value = ` {"${cstr}", U() },`;
|
|
var charstring = "";
|
|
Bedstead({
|
|
arguments: args,
|
|
print: printed => charstring += printed
|
|
}).then(() => {
|
|
document.getElementById("rendered")
|
|
.setAttribute("d", charstring
|
|
.replaceAll(/<!--(?:[^-]|-[^-])*-->/g, "")
|
|
.replace(/^.* [hv]stem /, "")
|
|
.replace(/^cntrmask [01]* /, "")
|
|
.replaceAll(/(\S+ +\S+ +)rmoveto/g, "m$1")
|
|
.replaceAll(/ rlineto/g, "")
|
|
.replace(/ endchar/, ""));
|
|
});
|
|
}
|
|
function from_c(c) {
|
|
var re = /[0-7]+/g;
|
|
document.querySelector('#inpane').reset();
|
|
for (var row of document.querySelector('#pixels').rows) {
|
|
var match = re.exec(c);
|
|
if (match == null) break;
|
|
var rowbits = Number.parseInt(match[0], 8);
|
|
for (var pixel
|
|
of Array.from(row.querySelectorAll('input')).reverse()) {
|
|
pixel.checked = (rowbits & 1 != 0);
|
|
rowbits >>= 1;
|
|
}
|
|
}
|
|
update_glyph();
|
|
}
|
|
function key_handler(e) {
|
|
var dx = 0, dy = 0;
|
|
switch (e.key) {
|
|
case "ArrowLeft": dx = -1; break;
|
|
case "ArrowRight": dx = +1; break;
|
|
case "ArrowUp": dy = -1; break;
|
|
case "ArrowDown": dy = +1; break;
|
|
default: return;
|
|
}
|
|
var x = this.closest("td").cellIndex;
|
|
var y = this.closest("tr").rowIndex;
|
|
x = (x + dx + 5) % 5;
|
|
y = (y + dy + 9) % 9;
|
|
var target = document.querySelector('#pixels').rows[y].cells[x]
|
|
.querySelector('input');
|
|
target.focus();
|
|
e.preventDefault();
|
|
}
|
|
function drawing_click(e) {
|
|
// At least on FF 140, SVGMatrix doesn't have .transformPoint()
|
|
// so we turn it into a DOMMatrix, which does.
|
|
var m = DOMMatrix.fromMatrix(this.getScreenCTM().inverse());
|
|
var pt = m.transformPoint({x: e.clientX, y: e.clientY});
|
|
var x = Math.floor(pt.x / 100) - 1;
|
|
var y = Math.floor(pt.y / 100) - 1;
|
|
var target = document.querySelector('#pixels').rows[y].cells[x]
|
|
.querySelector('input');
|
|
target.click();
|
|
e.preventDefault();
|
|
}
|
|
function init() {
|
|
for (var e of document.querySelectorAll('#pixels input')) {
|
|
e.onchange = e => update_glyph(true);
|
|
e.onkeydown = key_handler;
|
|
}
|
|
document.querySelector('#c').oninput = function(e) {
|
|
from_c(this.value);
|
|
update_glyph(false);
|
|
};
|
|
document.querySelector('#drawing').onclick = drawing_click;
|
|
update_glyph(true);
|
|
}
|
|
import("./bedstead.mjs").then((module) => {
|
|
Bedstead = module.default;
|
|
// This script is loaded asynchronously, so make sure the DOM is
|
|
// loaded before touching it.
|
|
if (document.readyState === "loading")
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
else
|
|
init();
|
|
});
|
|
]]>
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div id="inout">
|
|
<form id="inpane">
|
|
<table id="pixels">
|
|
<tr>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
<td><input type="checkbox"/></td>
|
|
</tr>
|
|
</table>
|
|
</form>
|
|
<div id="outpane">
|
|
<svg xmlns="http://www.w3.org/2000/svg" id="drawing"
|
|
viewBox="100 100 500 900">
|
|
<g transform="scale(1,-1) translate(0,-800)">
|
|
<path id="rendered" fill="currentColor"/>
|
|
</g>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<p><input id="c" type="text" size="39"/></p>
|
|
<h2>Bedstead Editor</h2>
|
|
<p>This page allows you to design glyphs for
|
|
<a href=".">Bedstead</a>.
|
|
Click pixels in the grid on the left to turn them on and off.
|
|
The drawing on the right shows the rendered glyph, which will be
|
|
identical to the input until you start drawing diagonal lines.
|
|
The box below the grid shows the pixels encoded for adding to
|
|
<code>bedstead.c</code>.
|
|
You can also edit that box directly, or paste designs into it.</p>
|
|
<div class="smallprint">
|
|
<p>This editor contains code from Emscripten and musl libc under
|
|
the following licence:</p>
|
|
<p>Copyright 2010-2022 The Emscripten Authors</p>
|
|
<p>Copyright © 2005-2020 Rich Felker, et al.</p>
|
|
<p>Copyright (C) 2011 by Valentin Ochs</p>
|
|
<p>Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:</p>
|
|
|
|
<p>The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.</p>
|
|
|
|
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>
|
|
</div>
|
|
</body>
|
|
</html>
|