diff --git a/assets/flipnote-editor/paint6.png b/assets/flipnote-editor/paint6.png new file mode 100644 index 0000000..a4b6a66 Binary files /dev/null and b/assets/flipnote-editor/paint6.png differ diff --git a/assets/flipnote-editor/paint6_Adv.png b/assets/flipnote-editor/paint6_Adv.png new file mode 100644 index 0000000..146a7d9 Binary files /dev/null and b/assets/flipnote-editor/paint6_Adv.png differ diff --git a/assets/flipnote-editor/paint7.png b/assets/flipnote-editor/paint7.png new file mode 100644 index 0000000..f42c5f3 Binary files /dev/null and b/assets/flipnote-editor/paint7.png differ diff --git a/assets/flipnote-editor/paint7_Adv.png b/assets/flipnote-editor/paint7_Adv.png new file mode 100644 index 0000000..3721a09 Binary files /dev/null and b/assets/flipnote-editor/paint7_Adv.png differ diff --git a/assets/flipnote-editor/paint8.png b/assets/flipnote-editor/paint8.png new file mode 100644 index 0000000..429eb28 Binary files /dev/null and b/assets/flipnote-editor/paint8.png differ diff --git a/assets/flipnote-editor/paint8_Adv.png b/assets/flipnote-editor/paint8_Adv.png new file mode 100644 index 0000000..47c5ead Binary files /dev/null and b/assets/flipnote-editor/paint8_Adv.png differ diff --git a/assets/flipnote-editor/paper-placeholder.png b/assets/flipnote-editor/paper-placeholder.png new file mode 100644 index 0000000..7473ebc Binary files /dev/null and b/assets/flipnote-editor/paper-placeholder.png differ diff --git a/assets/flipnote-editor/paperB.png b/assets/flipnote-editor/paperB.png new file mode 100644 index 0000000..327bbf7 Binary files /dev/null and b/assets/flipnote-editor/paperB.png differ diff --git a/assets/flipnote-editor/paperW.png b/assets/flipnote-editor/paperW.png new file mode 100644 index 0000000..0d9ef56 Binary files /dev/null and b/assets/flipnote-editor/paperW.png differ diff --git a/assets/flipnote-editor/paste.png b/assets/flipnote-editor/paste.png new file mode 100644 index 0000000..fc96224 Binary files /dev/null and b/assets/flipnote-editor/paste.png differ diff --git a/assets/flipnote-editor/pen.png b/assets/flipnote-editor/pen.png new file mode 100644 index 0000000..3a1ebb9 Binary files /dev/null and b/assets/flipnote-editor/pen.png differ diff --git a/assets/flipnote-editor/pen1.png b/assets/flipnote-editor/pen1.png new file mode 100644 index 0000000..edbf6c0 Binary files /dev/null and b/assets/flipnote-editor/pen1.png differ diff --git a/assets/flipnote-editor/pen1_Adv.png b/assets/flipnote-editor/pen1_Adv.png new file mode 100644 index 0000000..3b702cc Binary files /dev/null and b/assets/flipnote-editor/pen1_Adv.png differ diff --git a/assets/flipnote-editor/pen2.png b/assets/flipnote-editor/pen2.png new file mode 100644 index 0000000..a9b2555 Binary files /dev/null and b/assets/flipnote-editor/pen2.png differ diff --git a/assets/flipnote-editor/pen2_Adv.png b/assets/flipnote-editor/pen2_Adv.png new file mode 100644 index 0000000..40f7590 Binary files /dev/null and b/assets/flipnote-editor/pen2_Adv.png differ diff --git a/assets/flipnote-editor/pen3.png b/assets/flipnote-editor/pen3.png new file mode 100644 index 0000000..16d6b16 Binary files /dev/null and b/assets/flipnote-editor/pen3.png differ diff --git a/assets/flipnote-editor/pen3_Adv.png b/assets/flipnote-editor/pen3_Adv.png new file mode 100644 index 0000000..40420bc Binary files /dev/null and b/assets/flipnote-editor/pen3_Adv.png differ diff --git a/assets/flipnote-editor/pen4.png b/assets/flipnote-editor/pen4.png new file mode 100644 index 0000000..e599ea9 Binary files /dev/null and b/assets/flipnote-editor/pen4.png differ diff --git a/assets/flipnote-editor/pen4_Adv.png b/assets/flipnote-editor/pen4_Adv.png new file mode 100644 index 0000000..77e6108 Binary files /dev/null and b/assets/flipnote-editor/pen4_Adv.png differ diff --git a/assets/flipnote-editor/pen5.png b/assets/flipnote-editor/pen5.png new file mode 100644 index 0000000..7e92d6b Binary files /dev/null and b/assets/flipnote-editor/pen5.png differ diff --git a/assets/flipnote-editor/pen5_Adv.png b/assets/flipnote-editor/pen5_Adv.png new file mode 100644 index 0000000..f14e533 Binary files /dev/null and b/assets/flipnote-editor/pen5_Adv.png differ diff --git a/assets/flipnote-editor/pen6.png b/assets/flipnote-editor/pen6.png new file mode 100644 index 0000000..153f305 Binary files /dev/null and b/assets/flipnote-editor/pen6.png differ diff --git a/assets/flipnote-editor/pen6_Adv.png b/assets/flipnote-editor/pen6_Adv.png new file mode 100644 index 0000000..62a4460 Binary files /dev/null and b/assets/flipnote-editor/pen6_Adv.png differ diff --git a/assets/flipnote-editor/pen7.png b/assets/flipnote-editor/pen7.png new file mode 100644 index 0000000..6fbd9fd Binary files /dev/null and b/assets/flipnote-editor/pen7.png differ diff --git a/assets/flipnote-editor/pen7_Adv.png b/assets/flipnote-editor/pen7_Adv.png new file mode 100644 index 0000000..b95bb72 Binary files /dev/null and b/assets/flipnote-editor/pen7_Adv.png differ diff --git a/assets/flipnote-editor/pen8.png b/assets/flipnote-editor/pen8.png new file mode 100644 index 0000000..a45ba61 Binary files /dev/null and b/assets/flipnote-editor/pen8.png differ diff --git a/assets/flipnote-editor/pen8_Adv.png b/assets/flipnote-editor/pen8_Adv.png new file mode 100644 index 0000000..3e6cdde Binary files /dev/null and b/assets/flipnote-editor/pen8_Adv.png differ diff --git a/assets/flipnote-editor/play.png b/assets/flipnote-editor/play.png new file mode 100644 index 0000000..5a696e1 Binary files /dev/null and b/assets/flipnote-editor/play.png differ diff --git a/assets/flipnote-editor/previous-frame.png b/assets/flipnote-editor/previous-frame.png new file mode 100644 index 0000000..4f5cb6e Binary files /dev/null and b/assets/flipnote-editor/previous-frame.png differ diff --git a/assets/flipnote-editor/redo.png b/assets/flipnote-editor/redo.png new file mode 100644 index 0000000..c0d8d4e Binary files /dev/null and b/assets/flipnote-editor/redo.png differ diff --git a/assets/flipnote-editor/redo_grey.png b/assets/flipnote-editor/redo_grey.png new file mode 100644 index 0000000..6bf9b1e Binary files /dev/null and b/assets/flipnote-editor/redo_grey.png differ diff --git a/assets/flipnote-editor/resize_larger.png b/assets/flipnote-editor/resize_larger.png new file mode 100644 index 0000000..1135e52 Binary files /dev/null and b/assets/flipnote-editor/resize_larger.png differ diff --git a/assets/flipnote-editor/resize_smaller.png b/assets/flipnote-editor/resize_smaller.png new file mode 100644 index 0000000..767d82c Binary files /dev/null and b/assets/flipnote-editor/resize_smaller.png differ diff --git a/assets/flipnote-editor/rotate_anticlockwise.png b/assets/flipnote-editor/rotate_anticlockwise.png new file mode 100644 index 0000000..f7e977a Binary files /dev/null and b/assets/flipnote-editor/rotate_anticlockwise.png differ diff --git a/assets/flipnote-editor/rotate_clockwise.png b/assets/flipnote-editor/rotate_clockwise.png new file mode 100644 index 0000000..d93fccc Binary files /dev/null and b/assets/flipnote-editor/rotate_clockwise.png differ diff --git a/assets/flipnote-editor/selbase.png b/assets/flipnote-editor/selbase.png new file mode 100644 index 0000000..815a791 Binary files /dev/null and b/assets/flipnote-editor/selbase.png differ diff --git a/assets/flipnote-editor/select.png b/assets/flipnote-editor/select.png new file mode 100644 index 0000000..fdf9cd8 Binary files /dev/null and b/assets/flipnote-editor/select.png differ diff --git a/assets/flipnote-editor/select_pressed.png b/assets/flipnote-editor/select_pressed.png new file mode 100644 index 0000000..7c526f8 Binary files /dev/null and b/assets/flipnote-editor/select_pressed.png differ diff --git a/assets/flipnote-editor/select_y.png b/assets/flipnote-editor/select_y.png new file mode 100644 index 0000000..1561cc1 Binary files /dev/null and b/assets/flipnote-editor/select_y.png differ diff --git a/assets/flipnote-editor/selectionCopy.png b/assets/flipnote-editor/selectionCopy.png new file mode 100644 index 0000000..74edf71 Binary files /dev/null and b/assets/flipnote-editor/selectionCopy.png differ diff --git a/assets/flipnote-editor/selectionCut.png b/assets/flipnote-editor/selectionCut.png new file mode 100644 index 0000000..ef18426 Binary files /dev/null and b/assets/flipnote-editor/selectionCut.png differ diff --git a/assets/flipnote-editor/shiftl.png b/assets/flipnote-editor/shiftl.png new file mode 100644 index 0000000..38a0992 Binary files /dev/null and b/assets/flipnote-editor/shiftl.png differ diff --git a/assets/flipnote-editor/shiftl_active.png b/assets/flipnote-editor/shiftl_active.png new file mode 100644 index 0000000..2214272 Binary files /dev/null and b/assets/flipnote-editor/shiftl_active.png differ diff --git a/assets/flipnote-editor/soundBarEmpry.png b/assets/flipnote-editor/soundBarEmpry.png new file mode 100644 index 0000000..c610bce Binary files /dev/null and b/assets/flipnote-editor/soundBarEmpry.png differ diff --git a/assets/flipnote-editor/soundImport1.png b/assets/flipnote-editor/soundImport1.png new file mode 100644 index 0000000..1776acc Binary files /dev/null and b/assets/flipnote-editor/soundImport1.png differ diff --git a/assets/flipnote-editor/soundImport1alt.png b/assets/flipnote-editor/soundImport1alt.png new file mode 100644 index 0000000..841558b Binary files /dev/null and b/assets/flipnote-editor/soundImport1alt.png differ diff --git a/assets/flipnote-editor/soundImport2.png b/assets/flipnote-editor/soundImport2.png new file mode 100644 index 0000000..4e929ae Binary files /dev/null and b/assets/flipnote-editor/soundImport2.png differ diff --git a/assets/flipnote-editor/soundImport2alt.png b/assets/flipnote-editor/soundImport2alt.png new file mode 100644 index 0000000..8eb7771 Binary files /dev/null and b/assets/flipnote-editor/soundImport2alt.png differ diff --git a/assets/flipnote-editor/soundImport3.png b/assets/flipnote-editor/soundImport3.png new file mode 100644 index 0000000..815ddd1 Binary files /dev/null and b/assets/flipnote-editor/soundImport3.png differ diff --git a/assets/flipnote-editor/soundImport3alt.png b/assets/flipnote-editor/soundImport3alt.png new file mode 100644 index 0000000..692442c Binary files /dev/null and b/assets/flipnote-editor/soundImport3alt.png differ diff --git a/assets/flipnote-editor/soundPlay1.png b/assets/flipnote-editor/soundPlay1.png new file mode 100644 index 0000000..261d54c Binary files /dev/null and b/assets/flipnote-editor/soundPlay1.png differ diff --git a/assets/flipnote-editor/soundPlay2.png b/assets/flipnote-editor/soundPlay2.png new file mode 100644 index 0000000..c96875b Binary files /dev/null and b/assets/flipnote-editor/soundPlay2.png differ diff --git a/assets/flipnote-editor/soundPlay3.png b/assets/flipnote-editor/soundPlay3.png new file mode 100644 index 0000000..9fb9c8c Binary files /dev/null and b/assets/flipnote-editor/soundPlay3.png differ diff --git a/assets/flipnote-editor/soundRecord1.png b/assets/flipnote-editor/soundRecord1.png new file mode 100644 index 0000000..a3ee79a Binary files /dev/null and b/assets/flipnote-editor/soundRecord1.png differ diff --git a/assets/flipnote-editor/soundRecord2.png b/assets/flipnote-editor/soundRecord2.png new file mode 100644 index 0000000..05a1873 Binary files /dev/null and b/assets/flipnote-editor/soundRecord2.png differ diff --git a/assets/flipnote-editor/soundRecord3.png b/assets/flipnote-editor/soundRecord3.png new file mode 100644 index 0000000..e3eb6eb Binary files /dev/null and b/assets/flipnote-editor/soundRecord3.png differ diff --git a/assets/flipnote-editor/soundStop1.png b/assets/flipnote-editor/soundStop1.png new file mode 100644 index 0000000..cf2a4e0 Binary files /dev/null and b/assets/flipnote-editor/soundStop1.png differ diff --git a/assets/flipnote-editor/soundStop2.png b/assets/flipnote-editor/soundStop2.png new file mode 100644 index 0000000..f5942ae Binary files /dev/null and b/assets/flipnote-editor/soundStop2.png differ diff --git a/assets/flipnote-editor/soundStop3.png b/assets/flipnote-editor/soundStop3.png new file mode 100644 index 0000000..6361a15 Binary files /dev/null and b/assets/flipnote-editor/soundStop3.png differ diff --git a/assets/flipnote-editor/spacer.png b/assets/flipnote-editor/spacer.png new file mode 100644 index 0000000..4deaeab Binary files /dev/null and b/assets/flipnote-editor/spacer.png differ diff --git a/assets/flipnote-editor/speed1.png b/assets/flipnote-editor/speed1.png new file mode 100644 index 0000000..3b17b6f Binary files /dev/null and b/assets/flipnote-editor/speed1.png differ diff --git a/assets/flipnote-editor/speed2.png b/assets/flipnote-editor/speed2.png new file mode 100644 index 0000000..d00ee36 Binary files /dev/null and b/assets/flipnote-editor/speed2.png differ diff --git a/assets/flipnote-editor/speed3.png b/assets/flipnote-editor/speed3.png new file mode 100644 index 0000000..1c3eeba Binary files /dev/null and b/assets/flipnote-editor/speed3.png differ diff --git a/assets/flipnote-editor/speed4.png b/assets/flipnote-editor/speed4.png new file mode 100644 index 0000000..f54f596 Binary files /dev/null and b/assets/flipnote-editor/speed4.png differ diff --git a/assets/flipnote-editor/speed5.png b/assets/flipnote-editor/speed5.png new file mode 100644 index 0000000..99c308a Binary files /dev/null and b/assets/flipnote-editor/speed5.png differ diff --git a/assets/flipnote-editor/speed6.png b/assets/flipnote-editor/speed6.png new file mode 100644 index 0000000..33dbedc Binary files /dev/null and b/assets/flipnote-editor/speed6.png differ diff --git a/assets/flipnote-editor/speed7.png b/assets/flipnote-editor/speed7.png new file mode 100644 index 0000000..f940402 Binary files /dev/null and b/assets/flipnote-editor/speed7.png differ diff --git a/assets/flipnote-editor/speed8.png b/assets/flipnote-editor/speed8.png new file mode 100644 index 0000000..83b877b Binary files /dev/null and b/assets/flipnote-editor/speed8.png differ diff --git a/assets/flipnote-editor/stop.png b/assets/flipnote-editor/stop.png new file mode 100644 index 0000000..8c49415 Binary files /dev/null and b/assets/flipnote-editor/stop.png differ diff --git a/assets/flipnote-editor/tab-1.png b/assets/flipnote-editor/tab-1.png new file mode 100644 index 0000000..f50f191 Binary files /dev/null and b/assets/flipnote-editor/tab-1.png differ diff --git a/assets/flipnote-editor/tab-2.png b/assets/flipnote-editor/tab-2.png new file mode 100644 index 0000000..fd1becb Binary files /dev/null and b/assets/flipnote-editor/tab-2.png differ diff --git a/assets/flipnote-editor/tab-3.png b/assets/flipnote-editor/tab-3.png new file mode 100644 index 0000000..61237ca Binary files /dev/null and b/assets/flipnote-editor/tab-3.png differ diff --git a/assets/flipnote-editor/tab-4.png b/assets/flipnote-editor/tab-4.png new file mode 100644 index 0000000..5cd833f Binary files /dev/null and b/assets/flipnote-editor/tab-4.png differ diff --git a/assets/flipnote-editor/tab-5.png b/assets/flipnote-editor/tab-5.png new file mode 100644 index 0000000..ed8adbb Binary files /dev/null and b/assets/flipnote-editor/tab-5.png differ diff --git a/assets/flipnote-editor/tab1.png b/assets/flipnote-editor/tab1.png new file mode 100644 index 0000000..058f3a4 Binary files /dev/null and b/assets/flipnote-editor/tab1.png differ diff --git a/assets/flipnote-editor/tab1_selected.png b/assets/flipnote-editor/tab1_selected.png new file mode 100644 index 0000000..30ff56c Binary files /dev/null and b/assets/flipnote-editor/tab1_selected.png differ diff --git a/assets/flipnote-editor/tab2.png b/assets/flipnote-editor/tab2.png new file mode 100644 index 0000000..2d338fe Binary files /dev/null and b/assets/flipnote-editor/tab2.png differ diff --git a/assets/flipnote-editor/tab2_selected.png b/assets/flipnote-editor/tab2_selected.png new file mode 100644 index 0000000..9ae7d6d Binary files /dev/null and b/assets/flipnote-editor/tab2_selected.png differ diff --git a/assets/flipnote-editor/tab3.png b/assets/flipnote-editor/tab3.png new file mode 100644 index 0000000..f838d45 Binary files /dev/null and b/assets/flipnote-editor/tab3.png differ diff --git a/assets/flipnote-editor/tab3_selected.png b/assets/flipnote-editor/tab3_selected.png new file mode 100644 index 0000000..1620da5 Binary files /dev/null and b/assets/flipnote-editor/tab3_selected.png differ diff --git a/assets/flipnote-editor/tab4.png b/assets/flipnote-editor/tab4.png new file mode 100644 index 0000000..6eed17a Binary files /dev/null and b/assets/flipnote-editor/tab4.png differ diff --git a/assets/flipnote-editor/tab4_selected.png b/assets/flipnote-editor/tab4_selected.png new file mode 100644 index 0000000..552a2b9 Binary files /dev/null and b/assets/flipnote-editor/tab4_selected.png differ diff --git a/assets/flipnote-editor/tab5.png b/assets/flipnote-editor/tab5.png new file mode 100644 index 0000000..f59e11d Binary files /dev/null and b/assets/flipnote-editor/tab5.png differ diff --git a/assets/flipnote-editor/tab5_selected.png b/assets/flipnote-editor/tab5_selected.png new file mode 100644 index 0000000..565eb2e Binary files /dev/null and b/assets/flipnote-editor/tab5_selected.png differ diff --git a/assets/flipnote-editor/text-tool.js b/assets/flipnote-editor/text-tool.js new file mode 100644 index 0000000..3d1d085 --- /dev/null +++ b/assets/flipnote-editor/text-tool.js @@ -0,0 +1,273 @@ +(function (global) { + 'use strict'; + + // ndsbios.ttf uses 1024 units/em and a 64-unit pixel grid: 16px is + // its native size. The alphabetic baseline is 11px; allow 14px per line. + const FONT_SIZE = 16; + const BASELINE = 11; + const LINE_HEIGHT = 14; + const FONT = '16px "Flipnote Text NDS BIOS"'; + let fontPromise; + + function loadFont() { + if (!fontPromise) { + const face = new FontFace('Flipnote Text NDS BIOS', 'url("./assets/fonts/ndsbios.ttf")'); + const arabicFace = new FontFace('Flipnote Text Paxalah', 'url("./assets/fonts/paxalah.otf")'); + const arabic = global.FlipnoteArabicText ? Promise.resolve() : new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.src = './assets/flipnote-editor/arabic-text.js?v=1.1'; + script.onload = resolve; script.onerror = reject; document.head.append(script); + }); + fontPromise = Promise.all([face, arabicFace].map(font => font.load().then(loaded => document.fonts.add(loaded)))) + .then(() => arabic).then(() => global.FlipnoteArabicText.load()); + } + return fontPromise; + } + + function layoutText(value, anchor, width, measure, caretIndex = value.length) { + const glyphs = []; + let x = anchor.x, y = anchor.y, index = 0; + let caret = {x, y}; + for (const character of value) { + if (character === '\n') { + x = anchor.x; + y += LINE_HEIGHT; + } else { + const text = character === '\t' ? ' ' : character; + const advance = Math.max(0, Math.round(measure(text))); + if (x > anchor.x && x + advance > width) { + x = anchor.x; + y += LINE_HEIGHT; + if (index === caretIndex) caret = {x, y}; + } + glyphs.push({text, x, y}); + x += advance; + } + index += character.length; + if (index <= caretIndex) caret = {x, y}; + } + return {glyphs, caret}; + } + + function rasterize(context, glyphs, width = 256, height = 192) { + if (glyphs.some(glyph => glyph.bitmap)) return global.FlipnoteArabicText.rasterize(glyphs, width, height); + context.clearRect(0, 0, width, height); + context.font = FONT; + context.fontKerning = 'none'; + context.textBaseline = 'alphabetic'; + context.fillStyle = '#000'; + for (const glyph of glyphs) { + if (glyph.y >= height) break; + context.fillText(glyph.text, glyph.x, glyph.y + BASELINE); + } + const pixels = context.getImageData(0, 0, width, height).data; + return Uint8Array.from({length: width * height}, (_, index) => pixels[index * 4 + 3] >= 128 ? 1 : 0); + } + + function subtitleMask(value) { + if (global.FlipnoteArabicText.contains(value)) { + const result = global.FlipnoteArabicText.subtitleMask(value); + return {...result, ring: outline(result.mask)}; + } + const surface = document.createElement('canvas'); + surface.width = 256; surface.height = 192; + const context = surface.getContext('2d', {willReadFrequently: true}); + context.font = FONT; context.fontKerning = 'none'; + const measure = text => Array.from(text).reduce((sum, char) => sum + Math.round(context.measureText(char).width), 0); + const lines = []; + for (const paragraph of value.split('\n')) { + let line = ''; + for (const word of paragraph.split(' ')) { + if (line && measure((line + ' ' + word).trim()) > 244) { lines.push(line); line = ''; } + for (const char of (line ? ' ' : '') + word) { + if (line && measure(line + char) > 244) { lines.push(line.trimEnd()); line = ''; } + line += char; + } + } + lines.push(line.trim()); + } + if (lines.length > 2) throw new Error('Keep each subtitle to two lines. Split longer text into another subtitle.'); + const top = 192 - 4 - 12 - (lines.length - 1) * LINE_HEIGHT; + const glyphs = []; + lines.forEach((line, index) => { + let x = Math.floor((256 - measure(line)) / 2); + for (const char of line) { + glyphs.push({text: char, x, y: top + index * LINE_HEIGHT}); + x += measure(char); + } + }); + const mask = rasterize(context, glyphs); + return {mask, ring: outline(mask), lines}; + } + + function outline(mask) { + const ring = new Uint8Array(mask.length); + for (let y = 0; y < 192; y++) for (let x = 0; x < 256; x++) { + if (!mask[y * 256 + x]) continue; + for (let yy = Math.max(0, y - 1); yy <= Math.min(191, y + 1); yy++) + for (let xx = Math.max(0, x - 1); xx <= Math.min(255, x + 1); xx++) + if (!mask[yy * 256 + xx]) ring[yy * 256 + xx] = 1; + } + return ring; + } + + class FlipnoteTextTool { + constructor(editor, timeline, hooks) { + this.editor = editor; + this.timeline = timeline; + this.hooks = hooks; + this.enabled = false; + this.session = null; + this.request = 0; + this.fontLoaded = false; + this.fontError = false; + this.ready = loadFont().then(() => { this.fontLoaded = true; }).catch(() => { this.fontError = true; }); + this.raster = document.createElement('canvas'); + this.raster.width = editor.width; + this.raster.height = editor.height; + this.context = this.raster.getContext('2d', {willReadFrequently: true}); + this.input = document.createElement('textarea'); + this.input.className = 'flipnote-editor-text-input'; + this.input.setAttribute('aria-label', 'Flipnote text. Press Escape to finish.'); + this.input.setAttribute('dir', 'auto'); + this.input.setAttribute('autocapitalize', 'off'); + this.input.setAttribute('autocomplete', 'off'); + this.input.setAttribute('autocorrect', 'off'); + this.input.spellcheck = false; + this.input.maxLength = 4096; + this.input.tabIndex = -1; + document.body.append(this.input); + this.input.addEventListener('input', () => this.update()); + this.input.addEventListener('keydown', (event) => { + event.stopPropagation(); + if (event.key !== 'Escape' || event.isComposing) return; + event.preventDefault(); + this.finish(); + editor.canvasElement.focus({preventScroll: true}); + }); + this.input.addEventListener('keyup', () => this.resetCaret()); + this.input.addEventListener('blur', () => this.finish()); + document.addEventListener('selectionchange', () => { + if (document.activeElement === this.input) this.resetCaret(); + }); + document.addEventListener('pointerdown', (event) => { + if (event.target !== editor.canvasElement && event.target !== this.input) this.finish(); + }, true); + } + + toggle() { + if (this.enabled) { + this.disable(); + } else { + this.editor.finishStroke(); + this.editor.clearSelection(); + this.enabled = true; + this.editor.updateCursorMode(); + this.editor.renderCurrentFrame(); + } + } + + disable() { + this.finish(); + this.enabled = false; + this.request++; + this.editor.updateCursorMode(); + this.editor.renderCurrentFrame(); + } + + async begin(point) { + const request = ++this.request; + const frame = this.timeline.getFrame(this.timeline.currentFrame); + const layer = this.editor.activeLayer; + await this.ready; + if (!this.enabled || request !== this.request || !this.editor.allowEditing || this.timeline.playing + || frame !== this.timeline.getFrame(this.timeline.currentFrame) || layer !== this.editor.activeLayer) return; + if (this.fontError) { + global.alert('The text fonts could not load. Reload the editor before using the Text tool.'); + return; + } + this.finish(); + this.session = { + frame, layer, base: frame.layers[layer].slice(), value: '', + anchor: {x: Math.max(0, Math.min(this.editor.width - 1, Math.floor(point.x))), + y: Math.max(0, Math.min(this.editor.height - 1, Math.floor(point.y)))}, + }; + this.input.value = ''; + this.input.focus({preventScroll: true}); + this.resetCaret(); + } + + layout() { + if (global.FlipnoteArabicText.contains(this.input.value)) { + return global.FlipnoteArabicText.layoutText(this.input.value, this.session.anchor, this.editor.width, this.input.selectionEnd); + } + this.context.font = FONT; + this.context.fontKerning = 'none'; + return layoutText(this.input.value, this.session.anchor, this.editor.width, + (text) => this.context.measureText(text).width, this.input.selectionEnd); + } + + update() { + const session = this.session; + if (!session) return; + const layer = session.frame.layers[session.layer]; + const previous = layer.slice(); + const ctx = this.context; + const layout = this.layout(); + const mask = rasterize(ctx, layout.glyphs, this.editor.width, this.editor.height); + for (let i = 0; i < layer.length; i++) layer[i] = session.base[i] || mask[i]; + if (!this.hooks.canStoreFrame(session.frame)) { + layer.set(previous); + this.input.value = session.value; + this.hooks.notifyFull(); + } else { + session.value = this.input.value; + this.hooks.markDirty(); + } + this.timeline.createThumbnails(); + this.resetCaret(); + } + + resetCaret() { + this.caretStartedAt = Date.now(); + this.editor.renderCurrentFrame(); + } + + renderCaret() { + if (!this.session || this.timeline.playing || document.activeElement !== this.input) return; + const caret = this.layout().caret; + const rect = this.editor.canvasElement.getBoundingClientRect(); + this.input.style.left = `${rect.left + Math.min(caret.x, this.editor.width - 1) * rect.width / this.editor.width}px`; + this.input.style.top = `${rect.top + Math.min(caret.y, this.editor.height - 1) * rect.height / this.editor.height}px`; + if ((Date.now() - this.caretStartedAt) % 1000 >= 500 || caret.y >= this.editor.height) return; + const ctx = this.editor.ctx; + ctx.save(); + ctx.globalAlpha = 1; + ctx.globalCompositeOperation = 'difference'; + ctx.fillStyle = '#fff'; + ctx.fillRect(Math.max(0, Math.min(caret.x, this.editor.width - 1)), caret.y, 1, caret.height || BASELINE + 1); + ctx.restore(); + } + + finish() { + this.request++; + const session = this.session; + if (!session) return; + this.session = null; + const layer = session.frame.layers[session.layer]; + const changed = layer.some((pixel, i) => pixel !== session.base[i]); + if (changed) { + const index = this.timeline.frames.indexOf(session.frame); + if (index >= 0) this.timeline.updateFrame(index); + } + if (document.activeElement === this.input) this.input.blur(); + this.editor.renderCurrentFrame(); + } + } + + FlipnoteTextTool.layoutText = layoutText; + FlipnoteTextTool.loadFont = loadFont; + FlipnoteTextTool.subtitleMask = subtitleMask; + FlipnoteTextTool.metrics = {fontSize: FONT_SIZE, baseline: BASELINE, lineHeight: LINE_HEIGHT}; + global.FlipnoteTextTool = FlipnoteTextTool; +})(typeof window !== 'undefined' ? window : globalThis); diff --git a/assets/flipnote-editor/transform.png b/assets/flipnote-editor/transform.png new file mode 100644 index 0000000..0a638cd Binary files /dev/null and b/assets/flipnote-editor/transform.png differ diff --git a/assets/flipnote-editor/transform_active.png b/assets/flipnote-editor/transform_active.png new file mode 100644 index 0000000..f46b9d2 Binary files /dev/null and b/assets/flipnote-editor/transform_active.png differ diff --git a/assets/flipnote-editor/undo.png b/assets/flipnote-editor/undo.png new file mode 100644 index 0000000..2167650 Binary files /dev/null and b/assets/flipnote-editor/undo.png differ diff --git a/assets/flipnote-editor/undo_grey.png b/assets/flipnote-editor/undo_grey.png new file mode 100644 index 0000000..6472f6c Binary files /dev/null and b/assets/flipnote-editor/undo_grey.png differ diff --git a/assets/flipnote-editor/webm.png b/assets/flipnote-editor/webm.png new file mode 100644 index 0000000..268553b Binary files /dev/null and b/assets/flipnote-editor/webm.png differ