diff --git a/scss/style.scss b/scss/style.scss index 7d304d9..a813b88 100644 --- a/scss/style.scss +++ b/scss/style.scss @@ -148,4 +148,13 @@ h1, h2, h3, h4, h5, h6 { background: #f08cc666; } } +} + +.import-modal--controller { + width: 80vw; + textarea { + display: block; + width: 100%; + height: 40vh; + } } \ No newline at end of file diff --git a/ts/Import.ts b/ts/Import.ts new file mode 100644 index 0000000..1cc4aaf --- /dev/null +++ b/ts/Import.ts @@ -0,0 +1,49 @@ +import { AbstractBaseController } from "./AbstractController"; +import { CharCollection } from "./font"; + +export class ImportModal extends AbstractBaseController { + + private input = document.createElement("textarea"); + + private importButton = (() => { + let elm = document.createElement("button"); + elm.textContent = "Import"; + + return elm; + })(); + + private hideButton = (() => { + let elm = document.createElement("button"); + elm.textContent = "Close"; + + return elm; + })(); + + constructor( + charCollection: CharCollection, + ) { + super('import-modal', document.createElement('dialog')); + + this.container.append( + this.hideButton, + this.input, + this.importButton, + ); + + this.hideButton.addEventListener("click", () => { + this.container.close(); + }); + + this.importButton.addEventListener("click", () => { + let subject = this.input.value; + subject = subject.replace(/\s*\/\/.*/g, ""); + charCollection.importHexBlob(subject); + + this.container.close(); + }); + } + + public show() { + this.container.showModal(); + } +} \ No newline at end of file diff --git a/ts/font.ts b/ts/font.ts index 72c9594..0441ae6 100644 --- a/ts/font.ts +++ b/ts/font.ts @@ -35,10 +35,10 @@ export class Glyph { private exportHexBlob5x8(): string { let out = ""; - for( let c = 0; c < 5; c++ ) { + for (let c = 0; c < 5; c++) { let char1 = 0; - for( let r = 0; r < 8; r++ ) { - if(this.data[r * this.columns + c]) { + for (let r = 0; r < 8; r++) { + if (this.data[r * this.columns + c]) { char1 += 1 << r; } } @@ -49,12 +49,28 @@ export class Glyph { return out; } + private importHexBlob5x8(data: string) { + let myregexp = /0x([0-9a-f]{2})/ig; + let match = myregexp.exec(data); + let i = 0; + while (match != null) { + const value = parseInt(match[1], 16); + for (let r = 0; r < 8; r++) { + this.data[r * this.columns + i] = !!(value & (1 << r)); + } + i++; + match = myregexp.exec(data); + } + + this.updateEmitter.trigger(); + } + private exportHexBlob9x16(): string { let out = ""; - for( let c = 0; c < 9; c++ ) { + for (let c = 0; c < 9; c++) { let char1 = 0; - for( let r = 0; r < 8; r++ ) { - if(this.data[r * this.columns + c]) { + for (let r = 0; r < 8; r++) { + if (this.data[r * this.columns + c]) { char1 += 1 << r; } } @@ -62,10 +78,10 @@ export class Glyph { out += "0x" + char1.toString(16).padStart(2, "0") + ", "; } - for( let c = 0; c < 9; c++ ) { + for (let c = 0; c < 9; c++) { let char1 = 0; - for( let r = 8; r < 16; r++ ) { - if(this.data[r * this.columns + c]) { + for (let r = 8; r < 16; r++) { + if (this.data[r * this.columns + c]) { char1 += 1 << (r - 8); } } @@ -76,6 +92,35 @@ export class Glyph { return out; } + private importHexBlob9x16(data: string) { + let myregexp = /0x([0-9a-f]{2})/ig; + let match = myregexp.exec(data); + let i = 0; + + // First set of 9 bytes for the first 8 rows + while (match != null && i < 9) { + const value = parseInt(match[1], 16); + for (let r = 0; r < 8; r++) { + this.data[r * this.columns + i] = !!(value & (1 << r)); + } + i++; + match = myregexp.exec(data); + } + + // Start the second set of 9 bytes for the second 8 rows from the current position + i = 0; // reset i for the second block of data + while (match != null && i < 9) { + const value = parseInt(match[1], 16); + for (let r = 8; r < 16; r++) { + this.data[r * this.columns + i] = !!(value & (1 << (r - 8))); + } + i++; + match = myregexp.exec(data); + } + + this.updateEmitter.trigger(); + } + public exportHexBlob(): string { let out = ""; switch (this.columns) { @@ -93,6 +138,20 @@ export class Glyph { return "{" + out.replace(/, $/, "") + "}"; } + public importHexBlob(data: string) { + switch (this.columns) { + // this is a hack - it works for now + case 5: + this.importHexBlob5x8(data); + break; + case 9: + this.importHexBlob9x16(data); + break; + default: + throw new Error('Invalid glyph size'); + } + } + public clear() { this.setData(new Array(this.rows * this.columns).fill(false)); } @@ -230,7 +289,7 @@ export class CharCollection { x.forEach((charText: string, code: number) => { if (!this.chars[code]) { - console.log('adding uknown char: ', code); + console.log('adding unknown char: ', code); this.add(new Char(code)); } @@ -248,6 +307,29 @@ export class CharCollection { return output.replace(/,\n$/, ""); } + public importHexBlob(data: string) { + const myregexp = /{([^}]+)}/ig; + let match = myregexp.exec(data); + let i = 0; + while (match != null) { + const value = match[1]; + + const size = value.split(',').length; + // todo: this is gross + if (size === 18) { + console.log('importing 9x16'); + this.chars[i].getGlyph(16, 9).importHexBlob(value); + } else if (size === 5) { + console.log('importing 5x8'); + this.chars[i].getGlyph(8, 5).importHexBlob(value); + } else { + throw new Error('Invalid glyph size ' + size); + } + i++; + match = myregexp.exec(data); + } + } + public clear() { for (const char of this.chars) { char.clear(); diff --git a/ts/index.ts b/ts/index.ts index c3c5c63..6a6c1b7 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -1,3 +1,4 @@ +import { ImportModal } from "./Import"; import { ASCII } from "./ascii" import { Char, CharCollection } from "./font"; import { EditableGlyphTable, GlyphTable } from "./table"; @@ -132,6 +133,14 @@ export const init = (async (root: HTMLElement) => { header.appendChild(clearButton); + const importButton = document.createElement('button'); + importButton.appendChild(document.createTextNode('Import')); + const im = new ImportModal(collection); + document.body.appendChild(im.getContainer()); + importButton.addEventListener('click', () => { im.show(); }); + + header.appendChild(importButton); + const previewElm = document.createElement('div'); previewElm.className = 'root-preview'; root.appendChild(previewElm);