|
|
|
@ -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(
|
|
|
|
|