diff --git a/css/icons.css b/css/icons.css index 214460d..45ab99a 100644 --- a/css/icons.css +++ b/css/icons.css @@ -202,3 +202,9 @@ -webkit-mask-image: url("../res/icons/squircle.svg"); mask-image: url("../res/icons/squircle.svg"); } + +.ui.inline-icon.icon-file-plus::after, +.ui.icon > .icon-file-plus { + -webkit-mask-image: url("../res/icons/file-plus.svg"); + mask-image: url("../res/icons/file-plus.svg"); +} diff --git a/index.html b/index.html index c5dddae..d4a3d9a 100644 --- a/index.html +++ b/index.html @@ -339,7 +339,7 @@
- v20240427.001 + v20240824.001
- + @@ -576,7 +576,7 @@ src="js/ui/tool/generic.js?v=3e678e0" type="text/javascript"> - + diff --git a/js/index.js b/js/index.js index 7d852aa..97277ff 100644 --- a/js/index.js +++ b/js/index.js @@ -1534,7 +1534,7 @@ async function upscaleAndDownload( body: JSON.stringify(data), }) .then((response) => response.json()) - .then((data) => { + .then(async (data) => { console.log(data); var link = document.createElement("a"); link.download = @@ -1554,6 +1554,7 @@ async function upscaleAndDownload( console.log("Add upscaled to resource"); const img = new Image(); img.src = link.href; + await img.decode(); tools.stamp.state.addResource(guid() + " (upscaled)", img); } if (download == true) { diff --git a/js/lib/commands.js b/js/lib/commands.js index 0dc492f..3b9a3ca 100644 --- a/js/lib/commands.js +++ b/js/lib/commands.js @@ -21,6 +21,14 @@ const commands = makeReadOnly( _history: [], /** The types of commands we can run (private) */ _types: {}, + + /** @type {Observer<{n: int, cancel: function}>} */ + get onundo() { return this._onundo; }, + _onundo: new Observer(), + + /** @type {Observer<{n: int, cancel: function}>} */ + get onredo() { return this._onredo; }, + _onredo: new Observer(), /** * Undoes the last commands in the history @@ -28,6 +36,12 @@ const commands = makeReadOnly( * @param {number} [n] Number of actions to undo */ async undo(n = 1) { + var cancelled = false; + await this._onundo.emit({ + n:n, + cancel: ()=>{cancelled=true;}, + }); + if (cancelled) return; for (var i = 0; i < n && this.current > -1; i++) { try { await this._history[this._current--].undo(); @@ -45,6 +59,12 @@ const commands = makeReadOnly( * @param {number} [n] Number of actions to redo */ async redo(n = 1) { + let cancelled = false; + await this._onredo.emit({ + n:n, + cancel: ()=>{cancelled=true;}, + }); + if (cancelled) return; for (var i = 0; i < n && this.current + 1 < this._history.length; i++) { try { await this._history[++this._current].redo(); diff --git a/js/lib/input.js b/js/lib/input.js index d5f48cf..1585f12 100644 --- a/js/lib/input.js +++ b/js/lib/input.js @@ -660,6 +660,9 @@ window.onkeyup = (evn) => { }); } + if (keyboard.keys[evn.code]._hold_to) + clearTimeout(keyboard.keys[evn.code]._hold_to); + keyboard.keys[evn.code] = { pressed: false, held: false, diff --git a/js/ui/tool/dream.js b/js/ui/tool/dream.js index 5d23d73..f12ecf7 100644 --- a/js/ui/tool/dream.js +++ b/js/ui/tool/dream.js @@ -3339,6 +3339,7 @@ function addControlNetToAlwaysOnScripts(state, initCanvas, maskCanvas) { //img2img? state.alwayson_scripts.controlnet.args = [ { + enabled: true, module: extensions.selectedControlNetModule, model: extensions.selectedControlNetModel, control_mode: document.getElementById("controlNetMode-select").value, @@ -3351,10 +3352,11 @@ function addControlNetToAlwaysOnScripts(state, initCanvas, maskCanvas) { } else { state.alwayson_scripts.controlnet.args = [ { + enabled: true, module: extensions.selectedControlNetModule, model: extensions.selectedControlNetModel, control_mode: document.getElementById("controlNetMode-select").value, - input_image: initimg, //initCanvas.toDataURL(), + image: initimg, //initCanvas.toDataURL(), mask: maskimg, //maskCanvas.toDataURL(), processor_res: 64, resize_mode: document.getElementById("controlNetResize-select").value, diff --git a/js/ui/tool/select.js b/js/ui/tool/select.js index f89da91..a1e69e7 100644 --- a/js/ui/tool/select.js +++ b/js/ui/tool/select.js @@ -13,6 +13,9 @@ const selectTransformTool = () => mouse.listen.world.btn.left.ondragstart.on(state.dragstartcb); mouse.listen.world.btn.left.ondrag.on(state.dragcb); mouse.listen.world.btn.left.ondragend.on(state.dragendcb); + + mouse.listen.world.btn.left.ondclick.on(state.dclickcb); + mouse.listen.world.btn.right.ondclick.on(state.drclickcb); // Canvas right mouse handler mouse.listen.world.btn.right.onclick.on(state.cancelcb); @@ -23,6 +26,10 @@ const selectTransformTool = () => // Layer system handlers uil.onactive.on(state.uilayeractivecb); + + // Undo + commands.onundo.on(state.undocb); + commands.onredo.on(state.redocb); // Registers keyboard shortcuts keyboard.onShortcut({ctrl: true, key: "KeyA"}, state.ctrlacb); @@ -34,6 +41,15 @@ const selectTransformTool = () => keyboard.onShortcut({ctrl: true, key: "KeyV"}, state.ctrlvcb); keyboard.onShortcut({ctrl: true, key: "KeyX"}, state.ctrlxcb); keyboard.onShortcut({key: "Equal"}, state.togglemirror); + + keyboard.onShortcut({key: "Enter"}, state.entercb); + keyboard.onShortcut({shift: true, key: "Enter"}, state.sentercb); + keyboard.onShortcut({ctrl: true, key: "Enter"}, state.ctentercb); + keyboard.onShortcut({ctrl: true, shift: true, key: "Enter"}, state.sctentercb); + keyboard.onShortcut({key: "Delete"}, state.delcb); + keyboard.onShortcut({shift: true, key: "Delete"}, state.sdelcb); + + keyboard.onShortcut({key: "Escape"}, state.escapecb); state.ctxmenu.mirrorSelectionCheckbox.disabled = true; state.selected = null; @@ -51,20 +67,34 @@ const selectTransformTool = () => mouse.listen.world.btn.left.ondragstart.clear(state.dragstartcb); mouse.listen.world.btn.left.ondrag.clear(state.dragcb); mouse.listen.world.btn.left.ondragend.clear(state.dragendcb); + + mouse.listen.world.btn.left.ondclick.clear(state.dclickcb); + mouse.listen.world.btn.right.ondclick.clear(state.drclickcb); mouse.listen.world.btn.right.onclick.clear(state.cancelcb); keyboard.listen.onkeyclick.clear(state.keyclickcb); keyboard.listen.onkeydown.clear(state.keydowncb); + keyboard.deleteShortcut(state.ctrlacb, "KeyA"); keyboard.deleteShortcut(state.ctrlsacb, "KeyA"); keyboard.deleteShortcut(state.ctrlccb, "KeyC"); keyboard.deleteShortcut(state.ctrlvcb, "KeyV"); keyboard.deleteShortcut(state.ctrlxcb, "KeyX"); keyboard.deleteShortcut(state.togglemirror, "Equal"); - + keyboard.deleteShortcut(state.entercb,"Enter"); + keyboard.deleteShortcut(state.sentercb,"Enter"); + keyboard.deleteShortcut(state.ctentercb,"Enter"); + keyboard.deleteShortcut(state.sctentercb,"Enter"); + keyboard.deleteShortcut(state.delcb,"Delete"); + keyboard.deleteShortcut(state.sdelcb,"Delete"); + keyboard.deleteShortcut(state.escapecb,"Escape"); + uil.onactive.clear(state.uilayeractivecb); + commands.onundo.clear(state.undocb); + commands.onredo.clear(state.redocb); + // Clear any selections state.reset(); @@ -85,6 +115,9 @@ const selectTransformTool = () => state.snapToGrid = true; state.keepAspectRatio = true; state.block_res_change = true; + + state.toNewLayer = false; + state.useClipboard = !!( navigator.clipboard && navigator.clipboard.write ); // Use it by default if supported @@ -179,6 +212,19 @@ const selectTransformTool = () => ); } }; + + // Undo/Redo Handling, reset state before Undo/Redo + state.undocb= (undo)=>{ + if (state.selected){ + // Cancel so undo shortcut effectively undoes the current transform, unless requesting multiple steps + if (state.selectionTransformed() && undo.n<=1) + undo.cancel(); + state.reset(false); + } + } + state.redocb= (redo)=>{ + if (state.selected){ state.reset(false); } + } // Mirroring state.togglemirror = () => { @@ -251,94 +297,70 @@ const selectTransformTool = () => // Handles left mouse clicks state.clickcb = (evn) => { - if ( - state.selected && - !( - state.selected.rotation === 0 && - state.selected.scale.x === 1 && - state.selected.scale.y === 1 && - state.selected.position.x === state.original.sx && - state.selected.position.y === state.original.sy && - !state.mirrorSelection && - state.original.layer === uil.layer - ) && - !isCanvasBlank( - 0, - 0, - state.selected.canvas.width, - state.selected.canvas.height, - state.selected.canvas - ) - ) { - // Put original image back - state.original.layer.ctx.drawImage( - state.selected.canvas, - state.original.x, - state.original.y - ); - - // Erase Original Selection Area - commands.runCommand( - "eraseImage", - "Transform Tool Erase", - { - layer: state.original.layer, - x: state.original.x, - y: state.original.y, - w: state.selected.canvas.width, - h: state.selected.canvas.height, - }, - { - extra: { - log: `Erased original selection area at x: ${state.original.x}, y: ${state.original.y}, width: ${state.selected.canvas.width}, height: ${state.selected.canvas.height} from layer ${state.original.layer.id}`, - }, - } - ); - - // Draw Image - const {canvas, bb} = cropCanvas(state.originalDisplayLayer.canvas, { - border: 10, - }); - - let commandLog = ""; - const addline = (v, newline = true) => { - commandLog += v; - if (newline) commandLog += "\n"; - }; - - addline( - `Draw selected area to x: ${bb.x}, y: ${bb.y}, width: ${bb.w}, height: ${bb.h} to layer ${state.original.layer.id}` - ); - addline( - ` - translation: (x: ${state.selected.position.x}, y: ${state.selected.position.y})` - ); - addline( - ` - rotation : ${ - Math.round(1000 * ((180 * state.selected.rotation) / Math.PI)) / - 1000 - } degrees`, - false - ); - - commands.runCommand( - "drawImage", - "Transform Tool Apply", - { - image: canvas, - ...bb, - }, - { - extra: { - log: commandLog, - }, - } - ); - - state.reset(true); + if (state.selectionTransformed()) { + state.applyTransform(); } else { state.reset(); } }; + + // Check if selection has been transformed in any way. + state.selectionTransformed = ()=>{ + return state.selected && + !( + state.selected.rotation === 0 && + state.selected.scale.x === 1 && + state.selected.scale.y === 1 && + state.selected.position.x === state.original.sx && + state.selected.position.y === state.original.sy && + !state.mirrorSelection && + state.original.layer === uil.layer + ); + } + + // Handles left mouse double clicks - Select All Ctrl-A + // Holding shift key - Ctrl-Shift-A + state.dclickcb = (evn) => { + // Do nothing if Ctrl Key is held for panning + if (state.selected || evn.evn.ctrlKey) return; + let shift = evn.evn.shiftKey; + // Wait so clickcb doesn't immediately deselect. + state.dclickcb_timeout = state.dclickcb_timeout ?? window.setTimeout(async ()=>{ + state.dclickcb_timeout = null; + if (!state.selected && !selection.exists) { + if (shift) state.ctrlsacb(evn); + else state.ctrlacb(evn); + } + },300); + }; + + // Handles right mouse double clicks - Select topmost layer with content under pointer + // Holding shift key Selects the next topmost if current layer has visible content under pointer. + state.drclickcb = (evn) => { + if (state.selected) return; + // If shift key is held, and current layer is has visible pixels under pointer + // select topmost visible layer beneath the active layer + let shift = evn.evn.shiftKey + && !uil.active.hidden + && !isCanvasBlank(evn.x,evn.y,2,2,uil.active.canvas); + let layer = shift ? uil.active : null; + for (let l of uil.layers.toReversed()) { + if (shift) { + if (layer==l) shift = false; + } + else if (!l.hidden && !isCanvasBlank(evn.x,evn.y,2,2,l.canvas)){ + layer = l; + break; + } + } + if (layer) { + uil.active=layer; + state.dclickcb_timeout = state.dclickcb_timeout ?? window.setTimeout(async ()=>{ + state.dclickcb_timeout = null; + if (!state.selected && !selection.exists) { state.ctrlacb(evn); } + },300); + } + }; // Handles left mouse drag start events state.dragstartcb = (evn) => { @@ -513,33 +535,54 @@ const selectTransformTool = () => state.cancelcb = (evn) => { state.reset(); }; + + state.keydowncb = (evn) => { }; + + // Keyboard callbacks + state.keyclickcb = (evn) => { }; + + // Register Delete Shortcut + state.delcb = (evn) => { state.applyTransform(true,false,false,false); }; + + // Register Escape Shortcut + state.escapecb = (evn) => { state.reset(false); }; + + // Register Shift-Delete Shortcut - Delete Outside Selection and Apply + state.sdelcb = (evn) => { state.applyTransform(false,true,false,false); }; - // Keyboard callbacks (For now, they just handle the "delete" key) - state.keydowncb = (evn) => {}; + // Register Enter Shortcut - Apply Transform (Delegates to clickcb) + state.entercb = (evn) => { state.clickcb(evn); }; - state.keyclickcb = (evn) => { - switch (evn.code) { - case "Delete": - // Deletes selected area - state.selected && - commands.runCommand( - "eraseImage", - "Erase Area", - state.selected, - { - extra: { - log: `[Placeholder] Delete selected area. TODO it's also broken`, - }, - } - ); - state.ctxmenu.mirrorSelectionCheckbox.disabled = true; - state.selected = null; - state.redraw(); - } + // Register Ctrl-Enter Shortcut - Copy Selection to new layer, restore original + state.ctentercb = (evn) => { state.applyTransform(false,false,true,true); }; + + // Register Shift-Enter Shortcut - Move Selection to new layer + state.sentercb = (evn) => { state.applyTransform(false,false,true,false); }; + + // Register Ctrl-Shift-Enter Shortcut - Copy Visible Selection to new layer + state.sctentercb = async (evn) => { + var selectBB = + state.selected.bb != undefined + ? state.selected.bb + : state.backupBB; + const canvas = uil.getVisible(selectBB, { + categories: ["image", "user", "select-display"], + }); + await commands.runCommand("addLayer", "Added Layer"); + + await commands.runCommand("drawImage", "Transform Tool Apply", + { + image: canvas, + ...selectBB, + } + ); + state.reset(false); }; + // Register Ctrl-A Shortcut state.ctrlacb = () => { + state.reset(false); // Reset to preserve selected content try { const {bb} = cropCanvas(uil.canvas); select(bb); @@ -549,6 +592,8 @@ const selectTransformTool = () => }; state.ctrlsacb = () => { + state.reset(false); // Reset to preserve selected content + // Shift Key selects based on all visible layer information const tl = {x: Infinity, y: Infinity}; const br = {x: -Infinity, y: -Infinity}; @@ -667,6 +712,111 @@ const selectTransformTool = () => state.ctrlxcb = (evn) => { state.ctrlccb(evn, true); }; + + // Apply Transform and Reset State, optionally erase Selection or Clear Original Layer + // newLayer defaults to null, overriding the forced variants if explicitly set to false + // Only checks if Selection exists and content has been selected + // Does not check if content has been transformed, eg for deletion/applying to new layer + state.applyTransform = async (eraseSelected = false, clearLayer = false, newLayer = null, keepOriginal = false) => { + const isBlank = !state.selected || + isCanvasBlank( 0, 0, state.selected.canvas.width, state.selected.canvas.height, state.selected.canvas); + + // Just reset state if nothing is selected, unless Clearing layer + if (!state.selected || !clearLayer && isBlank ){ + state.reset(false); + return; + } + + // Put original image back + state.original.layer.ctx.drawImage( + state.selected.canvas, + state.original.x, + state.original.y + ); + + // Erase Entire Layer + if (clearLayer) await commands.runCommand( + "eraseImage", + "Transform Tool Erase", + { + ...state.original.layer.bb, + layer: state.original.layer, + }, + { + extra: { + log: `Erased layer ${state.original.layer.id}`, + }, + } + ); + // Erase Original Selection Area + else if (eraseSelected || !keepOriginal) await commands.runCommand( + "eraseImage", + "Transform Tool Erase", + { + layer: state.original.layer, + x: state.original.x, + y: state.original.y, + w: state.selected.canvas.width, + h: state.selected.canvas.height, + }, + { + extra: { + log: `Erased original selection area at x: ${state.original.x}, y: ${state.original.y}, width: ${state.selected.canvas.width}, height: ${state.selected.canvas.height} from layer ${state.original.layer.id}`, + }, + } + ); + + // Selection erased or was blank, no need to draw anything + if (eraseSelected || isBlank){ + state.reset(true); + return; + } + + // Draw Image + const {canvas, bb} = cropCanvas(state.originalDisplayLayer.canvas, { + border: 10, + }); + + if ( (newLayer ?? state.toNewLayer) && !clearLayer) + await commands.runCommand("addLayer", "Added Layer"); + + let commandLog = ""; + const addline = (v, newline = true) => { + commandLog += v; + if (newline) commandLog += "\n"; + }; + + addline( + `Draw selected area to x: ${bb.x}, y: ${bb.y}, width: ${bb.w}, height: ${bb.h} to layer ${state.original.layer.id}` + ); + addline( + ` - translation: (x: ${state.selected.position.x}, y: ${state.selected.position.y})` + ); + addline( + ` - rotation : ${ + Math.round(1000 * ((180 * state.selected.rotation) / Math.PI)) / + 1000 + } degrees`, + false + ); + + await commands.runCommand( + "drawImage", + "Transform Tool Apply", + { + image: canvas, + ...bb, + }, + { + extra: { + log: commandLog, + }, + } + ); + + state.reset(true); + } + }, populateContextMenu: (menu, state) => { if (!state.ctxmenu) { @@ -732,6 +882,15 @@ const selectTransformTool = () => state.ctxmenu.useClipboardLabel = clipboardCheckbox.checkbox; if (!(navigator.clipboard && navigator.clipboard.write)) clipboardCheckbox.checkbox.disabled = true; // Disable if not available + + // toNewLayer + state.ctxmenu.toNewLayerLabel = _toolbar_input.checkbox( + state, + "openoutpaint/select-toNewLayer", + "toNewLayer", + "Always Create New Layer", + "icon-file-plus" + ).checkbox; // Selection Peek Opacity state.ctxmenu.selectionPeekOpacitySlider = _toolbar_input.slider( @@ -757,7 +916,7 @@ const selectTransformTool = () => // Save button const saveSelectionButton = document.createElement("button"); saveSelectionButton.classList.add("button", "tool"); - saveSelectionButton.textContent = "Save Sel."; + saveSelectionButton.innerHTML = "Save Sel."; // nbsp as a quick hack for unwanted text wrapping saveSelectionButton.title = "Saves Selection"; saveSelectionButton.onclick = () => { downloadCanvas({ @@ -779,9 +938,25 @@ const selectTransformTool = () => tools.stamp.enable(); }; }; - + + const copyNewLayerButton = document.createElement("button"); + copyNewLayerButton.classList.add("button", "tool"); + copyNewLayerButton.textContent = "Layer"; + copyNewLayerButton.title = "Copies selection to a new Layer (Ctrl+Enter)"; + copyNewLayerButton.onclick = () => { state.applyTransform(false,false,true,true); }; + + // Dummy button for saving active selection + const ActiveSelectionButton = document.createElement("button"); + ActiveSelectionButton.classList.add("button", "tool"); + ActiveSelectionButton.textContent = "📄"; + ActiveSelectionButton.title = "Commands Applied to the Current Selection"; + ActiveSelectionButton.disabled = true; + + actionArray.appendChild(saveSelectionButton); actionArray.appendChild(createResourceButton); + actionArray.appendChild(copyNewLayerButton); + actionArray.appendChild(ActiveSelectionButton); // Some useful actions to do with selection const visibleActionArray = document.createElement("div"); @@ -790,8 +965,8 @@ const selectTransformTool = () => // Save Visible button const saveVisibleSelectionButton = document.createElement("button"); saveVisibleSelectionButton.classList.add("button", "tool"); - saveVisibleSelectionButton.textContent = "Save Vis."; - saveVisibleSelectionButton.title = "Saves Visible Selection"; + saveVisibleSelectionButton.innerHTML = "Save Vis."; // nbsp as a quick hack for unwanted text wrapping + saveVisibleSelectionButton.title = "Saves Visible Selection And Download"; saveVisibleSelectionButton.onclick = () => { console.debug(state.selected); console.debug(state.selected.bb); @@ -811,7 +986,7 @@ const selectTransformTool = () => // Save Visible as Resource Button const createVisibleResourceButton = document.createElement("button"); createVisibleResourceButton.classList.add("button", "tool"); - createVisibleResourceButton.textContent = "Vis. to Res."; + createVisibleResourceButton.textContent = "Resource"; createVisibleResourceButton.title = "Saves Visible Selection as a Resource"; createVisibleResourceButton.onclick = () => { @@ -830,8 +1005,52 @@ const selectTransformTool = () => }; }; + // Copy To Layer Buttons + const copyVisNewLayerButton = document.createElement("button"); + copyVisNewLayerButton.classList.add("button", "tool"); + copyVisNewLayerButton.textContent = "Layer"; + copyVisNewLayerButton.title = "Copies Visible Selection to a new Layer (Ctrl+Shift+Enter)"; + copyVisNewLayerButton.onclick = (e) => { state.sctentercb(e); }; + + // Dummy button for saving visible Selection + const VisibleSelectionButton = document.createElement("button"); + VisibleSelectionButton.classList.add("button", "tool"); + VisibleSelectionButton.textContent = "👁"; + VisibleSelectionButton.title = "Commands Applied to All Visible Content In the Selected Area"; + VisibleSelectionButton.disabled = true; + visibleActionArray.appendChild(saveVisibleSelectionButton); visibleActionArray.appendChild(createVisibleResourceButton); + visibleActionArray.appendChild(copyVisNewLayerButton); + visibleActionArray.appendChild(VisibleSelectionButton); + + const actionArrayRow3 = document.createElement("div"); + actionArrayRow3.classList.add("button-array"); + + // Clear Button + const applyClearButton = document.createElement("button"); + applyClearButton.classList.add("button", "tool"); + applyClearButton.textContent = "Isolate"; + applyClearButton.title = "Erases everything in the current layer outside the selection (Shift+Delete)"; + applyClearButton.onclick = () => { state.applyTransform(false,true,false,false); }; + + // Erase Button + const eraseSelectionButton = document.createElement("button"); + eraseSelectionButton.classList.add("button", "tool"); + eraseSelectionButton.textContent = "Erase"; + eraseSelectionButton.title = "Erases current selection (Delete)"; + eraseSelectionButton.onclick = () => { state.applyTransform(true,false,false,false); }; + + // Apply To New Layer button + const applyNewLayerButton = document.createElement("button"); + applyNewLayerButton.classList.add("button", "tool"); + applyNewLayerButton.textContent = "Extract"; + applyNewLayerButton.title = "Moves Selection to a New Layer (Shift+Enter)"; + applyNewLayerButton.onclick = () => { state.applyTransform(false,false,true,false); }; + + actionArrayRow3.appendChild(applyClearButton); + actionArrayRow3.appendChild(eraseSelectionButton); + actionArrayRow3.appendChild(applyNewLayerButton); // Disable buttons (if nothing is selected) state.ctxmenu.disableButtons = () => { @@ -839,6 +1058,11 @@ const selectTransformTool = () => createResourceButton.disabled = true; saveVisibleSelectionButton.disabled = true; createVisibleResourceButton.disabled = true; + applyNewLayerButton.disabled = true; + copyNewLayerButton.disabled = true; + applyClearButton.disabled = true; + eraseSelectionButton.disabled = true; + copyVisNewLayerButton.disabled = true; }; // Enable buttons (if something is selected) @@ -847,9 +1071,17 @@ const selectTransformTool = () => createResourceButton.disabled = ""; saveVisibleSelectionButton.disabled = ""; createVisibleResourceButton.disabled = ""; + applyNewLayerButton.disabled = ""; + copyNewLayerButton.disabled = ""; + applyClearButton.disabled = ""; + eraseSelectionButton.disabled = ""; + copyVisNewLayerButton.disabled = ""; }; + state.ctxmenu.actionArray = actionArray; state.ctxmenu.visibleActionArray = visibleActionArray; + + state.ctxmenu.actionArrayRow3 = actionArrayRow3; // Send Selection to Destination state.ctxmenu.sendSelected = document.createElement("select"); @@ -872,10 +1104,15 @@ const selectTransformTool = () => array.appendChild(state.ctxmenu.keepAspectRatioLabel); array.appendChild(state.ctxmenu.mirrorSelectionCheckbox); array.appendChild(state.ctxmenu.useClipboardLabel); + + array.appendChild(state.ctxmenu.toNewLayerLabel); + menu.appendChild(array); menu.appendChild(state.ctxmenu.selectionPeekOpacitySlider); menu.appendChild(state.ctxmenu.actionArray); menu.appendChild(state.ctxmenu.visibleActionArray); + menu.appendChild(state.ctxmenu.actionArrayRow3); + if (global.webui && global.webui.destinations) { while (state.ctxmenu.sendSelected.lastChild.value !== "None") { state.ctxmenu.sendSelected.removeChild( diff --git a/pages/embed.test.html b/pages/embed.test.html index 420c634..ee7c2e4 100644 --- a/pages/embed.test.html +++ b/pages/embed.test.html @@ -8,7 +8,7 @@