mirror of
https://github.com/Azornes/Comfyui-LayerForge.git
synced 2026-03-25 14:25:44 -03:00
Refactor canvas state change handling and layer removal
Replaces the onInteractionEnd callback with onStateChange for more consistent state change notifications. Adds a removeSelectedLayers method to Canvas for cleaner layer removal logic. Updates UI event handlers to use the new methods and callbacks, and ensures state is saved after relevant operations. Cleans up redundant updateOutput calls and streamlines output update logic.
This commit is contained in:
21
js/Canvas.js
21
js/Canvas.js
@@ -22,7 +22,7 @@ export class Canvas {
|
|||||||
this.selectedLayer = null;
|
this.selectedLayer = null;
|
||||||
this.selectedLayers = [];
|
this.selectedLayers = [];
|
||||||
this.onSelectionChange = null;
|
this.onSelectionChange = null;
|
||||||
this.onInteractionEnd = callbacks.onInteractionEnd || null;
|
this.onStateChange = callbacks.onStateChange || null;
|
||||||
this.lastMousePosition = {x: 0, y: 0};
|
this.lastMousePosition = {x: 0, y: 0};
|
||||||
|
|
||||||
this.viewport = {
|
this.viewport = {
|
||||||
@@ -78,19 +78,28 @@ export class Canvas {
|
|||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_notifyStateChange() {
|
||||||
|
if (this.onStateChange) {
|
||||||
|
this.onStateChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
saveState(replaceLast = false) {
|
saveState(replaceLast = false) {
|
||||||
this.canvasState.saveState(replaceLast);
|
this.canvasState.saveState(replaceLast);
|
||||||
this.incrementOperationCount();
|
this.incrementOperationCount();
|
||||||
|
this._notifyStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
undo() {
|
undo() {
|
||||||
this.canvasState.undo();
|
this.canvasState.undo();
|
||||||
this.incrementOperationCount();
|
this.incrementOperationCount();
|
||||||
|
this._notifyStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
redo() {
|
redo() {
|
||||||
this.canvasState.redo();
|
this.canvasState.redo();
|
||||||
this.incrementOperationCount();
|
this.incrementOperationCount();
|
||||||
|
this._notifyStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSelectionAfterHistory() {
|
updateSelectionAfterHistory() {
|
||||||
@@ -210,6 +219,16 @@ export class Canvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeSelectedLayers() {
|
||||||
|
if (this.selectedLayers.length > 0) {
|
||||||
|
this.saveState();
|
||||||
|
this.layers = this.layers.filter(l => !this.selectedLayers.includes(l));
|
||||||
|
this.updateSelection([]);
|
||||||
|
this.render();
|
||||||
|
this.saveState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getMouseWorldCoordinates(e) {
|
getMouseWorldCoordinates(e) {
|
||||||
const rect = this.canvas.getBoundingClientRect();
|
const rect = this.canvas.getBoundingClientRect();
|
||||||
|
|
||||||
|
|||||||
@@ -727,7 +727,7 @@ export class CanvasIO {
|
|||||||
this.canvas.layers.push(layer);
|
this.canvas.layers.push(layer);
|
||||||
this.canvas.selectedLayer = layer;
|
this.canvas.selectedLayer = layer;
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
|
this.canvas.saveState();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error('Error importing image:', error);
|
log.error('Error importing image:', error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,9 +172,6 @@ export class CanvasInteractions {
|
|||||||
if (interactionEnded) {
|
if (interactionEnded) {
|
||||||
this.canvas.saveState();
|
this.canvas.saveState();
|
||||||
this.canvas.saveStateToDB(true);
|
this.canvas.saveStateToDB(true);
|
||||||
if (this.canvas.onInteractionEnd) {
|
|
||||||
this.canvas.onInteractionEnd();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ export class CanvasLayers {
|
|||||||
this.canvasLayers.layers.splice(index, 1);
|
this.canvasLayers.layers.splice(index, 1);
|
||||||
this.canvasLayers.selectedLayer = this.canvasLayers.layers[this.canvasLayers.layers.length - 1] || null;
|
this.canvasLayers.selectedLayer = this.canvasLayers.layers[this.canvasLayers.layers.length - 1] || null;
|
||||||
this.canvasLayers.render();
|
this.canvasLayers.render();
|
||||||
|
this.canvasLayers.saveState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const log = createModuleLogger('Canvas_view');
|
|||||||
|
|
||||||
async function createCanvasWidget(node, widget, app) {
|
async function createCanvasWidget(node, widget, app) {
|
||||||
const canvas = new Canvas(node, widget, {
|
const canvas = new Canvas(node, widget, {
|
||||||
onInteractionEnd: () => updateOutput()
|
onStateChange: () => updateOutput()
|
||||||
});
|
});
|
||||||
const imageCache = new ImageCache();
|
const imageCache = new ImageCache();
|
||||||
|
|
||||||
@@ -375,11 +375,10 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
input.onchange = async (e) => {
|
input.onchange = async (e) => {
|
||||||
for (const file of e.target.files) {
|
for (const file of e.target.files) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = async (event) => {
|
reader.onload = (event) => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = async () => {
|
img.onload = () => {
|
||||||
canvas.addLayer(img);
|
canvas.addLayer(img);
|
||||||
await updateOutput();
|
|
||||||
};
|
};
|
||||||
img.src = event.target.result;
|
img.src = event.target.result;
|
||||||
};
|
};
|
||||||
@@ -391,11 +390,7 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
}),
|
}),
|
||||||
$el("button.painter-button.primary", {
|
$el("button.painter-button.primary", {
|
||||||
textContent: "Import Input",
|
textContent: "Import Input",
|
||||||
onclick: async () => {
|
onclick: () => canvas.importLatestImage()
|
||||||
if (await canvas.importLatestImage()) {
|
|
||||||
await updateOutput();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
$el("button.painter-button.primary", {
|
$el("button.painter-button.primary", {
|
||||||
textContent: "Paste Image",
|
textContent: "Paste Image",
|
||||||
@@ -481,6 +476,7 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
const height = parseInt(document.getElementById('canvas-height').value) || canvas.height;
|
const height = parseInt(document.getElementById('canvas-height').value) || canvas.height;
|
||||||
canvas.updateOutputAreaSize(width, height);
|
canvas.updateOutputAreaSize(width, height);
|
||||||
document.body.removeChild(dialog);
|
document.body.removeChild(dialog);
|
||||||
|
// updateOutput is triggered by saveState in updateOutputAreaSize
|
||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById('cancel-size').onclick = () => {
|
document.getElementById('cancel-size').onclick = () => {
|
||||||
@@ -490,27 +486,15 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
}),
|
}),
|
||||||
$el("button.painter-button.requires-selection", {
|
$el("button.painter-button.requires-selection", {
|
||||||
textContent: "Remove Layer",
|
textContent: "Remove Layer",
|
||||||
onclick: () => {
|
onclick: () => canvas.removeSelectedLayers()
|
||||||
if (canvas.selectedLayers.length > 0) {
|
|
||||||
canvas.saveState();
|
|
||||||
canvas.layers = canvas.layers.filter(l => !canvas.selectedLayers.includes(l));
|
|
||||||
canvas.updateSelection([]);
|
|
||||||
canvas.render();
|
|
||||||
canvas.saveState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
$el("button.painter-button.requires-selection", {
|
$el("button.painter-button.requires-selection", {
|
||||||
textContent: "Layer Up",
|
textContent: "Layer Up",
|
||||||
onclick: async () => {
|
onclick: () => canvas.moveLayerUp()
|
||||||
canvas.moveLayerUp();
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
$el("button.painter-button.requires-selection", {
|
$el("button.painter-button.requires-selection", {
|
||||||
textContent: "Layer Down",
|
textContent: "Layer Down",
|
||||||
onclick: async () => {
|
onclick: () => canvas.moveLayerDown()
|
||||||
canvas.moveLayerDown();
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
@@ -574,7 +558,6 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
canvas.updateSelection([newLayer]);
|
canvas.updateSelection([newLayer]);
|
||||||
canvas.render();
|
canvas.render();
|
||||||
canvas.saveState();
|
canvas.saveState();
|
||||||
await updateOutput();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error("Matting error:", error);
|
log.error("Matting error:", error);
|
||||||
alert(`Error during matting process: ${error.message}`);
|
alert(`Error during matting process: ${error.message}`);
|
||||||
@@ -743,28 +726,11 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
|
|
||||||
const triggerWidget = node.widgets.find(w => w.name === "trigger");
|
const triggerWidget = node.widgets.find(w => w.name === "trigger");
|
||||||
|
|
||||||
const updateOutput = async () => {
|
const updateOutput = () => {
|
||||||
|
|
||||||
|
|
||||||
triggerWidget.value = (triggerWidget.value + 1) % 99999999;
|
triggerWidget.value = (triggerWidget.value + 1) % 99999999;
|
||||||
app.graph.runStep();
|
// app.graph.runStep(); // Potentially not needed if we just want to mark dirty
|
||||||
};
|
};
|
||||||
|
|
||||||
const addUpdateToButton = (button) => {
|
|
||||||
if (button.textContent === "Undo" || button.textContent === "Redo" || button.title === "Open in Editor") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const origClick = button.onclick;
|
|
||||||
button.onclick = async (...args) => {
|
|
||||||
if (origClick) {
|
|
||||||
await origClick(...args);
|
|
||||||
}
|
|
||||||
await updateOutput();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
controlPanel.querySelectorAll('button').forEach(addUpdateToButton);
|
|
||||||
|
|
||||||
const canvasContainer = $el("div.painterCanvasContainer.painter-container", {
|
const canvasContainer = $el("div.painterCanvasContainer.painter-container", {
|
||||||
style: {
|
style: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@@ -833,7 +799,6 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
canvas.render();
|
canvas.render();
|
||||||
canvas.saveState();
|
canvas.saveState();
|
||||||
log.info("Dropped layer added and state saved.");
|
log.info("Dropped layer added and state saved.");
|
||||||
await updateOutput();
|
|
||||||
};
|
};
|
||||||
img.src = event.target.result;
|
img.src = event.target.result;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user