diff --git a/js/Canvas.js b/js/Canvas.js index 6c346f1..a92735c 100644 --- a/js/Canvas.js +++ b/js/Canvas.js @@ -22,7 +22,7 @@ export class Canvas { this.selectedLayer = null; this.selectedLayers = []; this.onSelectionChange = null; - this.onInteractionEnd = callbacks.onInteractionEnd || null; + this.onStateChange = callbacks.onStateChange || null; this.lastMousePosition = {x: 0, y: 0}; this.viewport = { @@ -78,19 +78,28 @@ export class Canvas { this.render(); } + _notifyStateChange() { + if (this.onStateChange) { + this.onStateChange(); + } + } + saveState(replaceLast = false) { this.canvasState.saveState(replaceLast); this.incrementOperationCount(); + this._notifyStateChange(); } undo() { this.canvasState.undo(); this.incrementOperationCount(); + this._notifyStateChange(); } redo() { this.canvasState.redo(); this.incrementOperationCount(); + this._notifyStateChange(); } 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) { const rect = this.canvas.getBoundingClientRect(); diff --git a/js/CanvasIO.js b/js/CanvasIO.js index c029b0a..05d06c1 100644 --- a/js/CanvasIO.js +++ b/js/CanvasIO.js @@ -727,7 +727,7 @@ export class CanvasIO { this.canvas.layers.push(layer); this.canvas.selectedLayer = layer; this.canvas.render(); - + this.canvas.saveState(); } catch (error) { log.error('Error importing image:', error); } diff --git a/js/CanvasInteractions.js b/js/CanvasInteractions.js index e730ac8..6132964 100644 --- a/js/CanvasInteractions.js +++ b/js/CanvasInteractions.js @@ -172,9 +172,6 @@ export class CanvasInteractions { if (interactionEnded) { this.canvas.saveState(); this.canvas.saveStateToDB(true); - if (this.canvas.onInteractionEnd) { - this.canvas.onInteractionEnd(); - } } } diff --git a/js/CanvasLayers.js b/js/CanvasLayers.js index 77714c3..072394c 100644 --- a/js/CanvasLayers.js +++ b/js/CanvasLayers.js @@ -158,6 +158,7 @@ export class CanvasLayers { this.canvasLayers.layers.splice(index, 1); this.canvasLayers.selectedLayer = this.canvasLayers.layers[this.canvasLayers.layers.length - 1] || null; this.canvasLayers.render(); + this.canvasLayers.saveState(); } } diff --git a/js/CanvasView.js b/js/CanvasView.js index 3358786..2c8dac0 100644 --- a/js/CanvasView.js +++ b/js/CanvasView.js @@ -12,7 +12,7 @@ const log = createModuleLogger('Canvas_view'); async function createCanvasWidget(node, widget, app) { const canvas = new Canvas(node, widget, { - onInteractionEnd: () => updateOutput() + onStateChange: () => updateOutput() }); const imageCache = new ImageCache(); @@ -375,11 +375,10 @@ async function createCanvasWidget(node, widget, app) { input.onchange = async (e) => { for (const file of e.target.files) { const reader = new FileReader(); - reader.onload = async (event) => { + reader.onload = (event) => { const img = new Image(); - img.onload = async () => { + img.onload = () => { canvas.addLayer(img); - await updateOutput(); }; img.src = event.target.result; }; @@ -391,11 +390,7 @@ async function createCanvasWidget(node, widget, app) { }), $el("button.painter-button.primary", { textContent: "Import Input", - onclick: async () => { - if (await canvas.importLatestImage()) { - await updateOutput(); - } - } + onclick: () => canvas.importLatestImage() }), $el("button.painter-button.primary", { textContent: "Paste Image", @@ -481,6 +476,7 @@ async function createCanvasWidget(node, widget, app) { const height = parseInt(document.getElementById('canvas-height').value) || canvas.height; canvas.updateOutputAreaSize(width, height); document.body.removeChild(dialog); + // updateOutput is triggered by saveState in updateOutputAreaSize }; document.getElementById('cancel-size').onclick = () => { @@ -490,27 +486,15 @@ async function createCanvasWidget(node, widget, app) { }), $el("button.painter-button.requires-selection", { textContent: "Remove Layer", - onclick: () => { - if (canvas.selectedLayers.length > 0) { - canvas.saveState(); - canvas.layers = canvas.layers.filter(l => !canvas.selectedLayers.includes(l)); - canvas.updateSelection([]); - canvas.render(); - canvas.saveState(); - } - } + onclick: () => canvas.removeSelectedLayers() }), $el("button.painter-button.requires-selection", { textContent: "Layer Up", - onclick: async () => { - canvas.moveLayerUp(); - } + onclick: () => canvas.moveLayerUp() }), $el("button.painter-button.requires-selection", { textContent: "Layer Down", - onclick: async () => { - canvas.moveLayerDown(); - } + onclick: () => canvas.moveLayerDown() }), ]), @@ -574,7 +558,6 @@ async function createCanvasWidget(node, widget, app) { canvas.updateSelection([newLayer]); canvas.render(); canvas.saveState(); - await updateOutput(); } catch (error) { log.error("Matting error:", error); 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 updateOutput = async () => { - - + const updateOutput = () => { 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", { style: { position: "absolute", @@ -833,7 +799,6 @@ async function createCanvasWidget(node, widget, app) { canvas.render(); canvas.saveState(); log.info("Dropped layer added and state saved."); - await updateOutput(); }; img.src = event.target.result; };