diff --git a/celstomp/js/ui/interaction-shortcuts.js b/celstomp/js/ui/interaction-shortcuts.js index 5359ed6..945227d 100644 --- a/celstomp/js/ui/interaction-shortcuts.js +++ b/celstomp/js/ui/interaction-shortcuts.js @@ -580,6 +580,47 @@ function _wireExtraKeyboardShortcuts() { }, true); } } + +function flipSelection(horizontal) { + if (!rectSelection.active) return; + const c = getFrameCanvas(rectSelection.L, rectSelection.F, rectSelection.key); + if (!c) return; + const ctx = c.getContext("2d", { willReadFrequently: true }); + if (!ctx) return; + + const selSnap = ctx.getImageData(rectSelection.x, rectSelection.y, rectSelection.w, rectSelection.h); + const fullSnap = ctx.getImageData(0, 0, contentW, contentH); + + beginGlobalHistoryStep(rectSelection.L, rectSelection.F, rectSelection.key); + + ctx.clearRect(rectSelection.x, rectSelection.y, rectSelection.w, rectSelection.h); + + const flipped = ctx.createImageData(rectSelection.w, rectSelection.h); + const src = selSnap.data; + const dst = flipped.data; + + for (let y = 0; y < rectSelection.h; y++) { + for (let x = 0; x < rectSelection.w; x++) { + const srcIdx = (y * rectSelection.w + x) * 4; + const dstY = horizontal ? y : (rectSelection.h - 1 - y); + const dstX = horizontal ? (rectSelection.w - 1 - x) : x; + const dstIdx = (dstY * rectSelection.w + dstX) * 4; + dst[dstIdx] = src[srcIdx]; + dst[dstIdx + 1] = src[srcIdx + 1]; + dst[dstIdx + 2] = src[srcIdx + 2]; + dst[dstIdx + 3] = src[srcIdx + 3]; + } + } + + ctx.putImageData(flipped, rectSelection.x, rectSelection.y); + + markGlobalHistoryDirty(); + commitGlobalHistoryStep(); + recomputeHasContent(rectSelection.L, rectSelection.F, rectSelection.key); + queueRenderAll(); + updateTimelineHasContent(rectSelection.F); +} + function wireKeyboardShortcuts() { if (document._celstompKeysWired) return; document._celstompKeysWired = true; @@ -749,6 +790,14 @@ function onWindowKeyDown(e) { return; } } + if (rectSelection.active && (e.key.toLowerCase() === "h" || e.key.toLowerCase() === "v")) { + const tag = e.target && e.target.tagName ? e.target.tagName.toUpperCase() : ""; + if (tag !== "INPUT" && tag !== "TEXTAREA" && tag !== "SELECT") { + e.preventDefault(); + flipSelection(e.key.toLowerCase() === "h"); + return; + } + } if ((e.key === "Delete" || e.key === "Backspace") && rectSelection.active) { const tag = e.target && e.target.tagName ? e.target.tagName.toUpperCase() : ""; if (tag !== "INPUT" && tag !== "TEXTAREA" && tag !== "SELECT") { diff --git a/celstomp/parts/modals.js b/celstomp/parts/modals.js index 5351362..3c71714 100644 --- a/celstomp/parts/modals.js +++ b/celstomp/parts/modals.js @@ -70,13 +70,18 @@ document.getElementById('part-modals').innerHTML = `