fix(inpaint): editor reset-all resets brush tool; wrap onConnectionsChange; load-race guard

- Reset all to default now returns the tool to Brush (it stayed on Erase).
- node.onConnectionsChange is wrapped instead of assigned, so a prototype /
  other-extension handler is chained, not clobbered (forward-safety).
- _loadImageFromURL / _loadImageFromDataURL / _loadMaskFromURL carry a load
  generation token: a late image/mask onload from a prior open no longer
  overwrites the current image, and a saved mask won't clobber fresh strokes
  (bails if painting / has undo history / a painted bbox).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pixaroma
2026-06-16 14:53:54 +03:00
co-authored by Claude Opus 4.8
parent 2ef7cd6cde
commit 754e0177d2
4 changed files with 23 additions and 8 deletions
+2
View File
@@ -336,6 +336,7 @@ export class InpaintCropEditor {
_setTool(v) { this.tool = v; }
_resetAll() {
this._setTool("add"); // back to Brush (was left on Erase after a reset)
this.brushSize = DEFAULT_BRUSH_SIZE;
this.maskOpacity = 0.5;
this.params.blend = 16;
@@ -352,6 +353,7 @@ export class InpaintCropEditor {
this.el.growSlider?.setValue(4);
this.el.ctxSlider?.setValue(24);
this.el.targetSlider?.setValue(1024);
this._toolGrid?.setActive?.("add");
this._blendModeGrid?.setActive?.("mask");
this._sizeModeGrid?.setActive?.("keep");
this._multipleGrid?.setActive?.(8);
+12 -8
View File
@@ -325,14 +325,18 @@ app.registerExtension({
};
api.addEventListener("executed", onExec);
node.onConnectionsChange = (type, slotIndex, connected) => {
if (type !== LiteGraph.INPUT) return;
if (node.inputs?.[slotIndex]?.name !== "image") return;
if (isGraphLoading()) return;
node._pixInpaintSourceURL = null;
if (node.properties) delete node.properties.pixInpaintSource;
if (connected) refreshSourcePreview();
else restoreNodePreview(parts, "{}", node);
// wrap (don't clobber) any existing handler from the prototype / another ext;
// forward all args, then run our image-input source-preview logic.
const origConnChange = node.onConnectionsChange;
node.onConnectionsChange = function (type, slotIndex, connected) {
const r = origConnChange?.apply(this, arguments);
if (type === LiteGraph.INPUT && node.inputs?.[slotIndex]?.name === "image" && !isGraphLoading()) {
node._pixInpaintSourceURL = null;
if (node.properties) delete node.properties.pixInpaintSource;
if (connected) refreshSourcePreview();
else restoreNodePreview(parts, "{}", node);
}
return r;
};
const origRemoved = node.onRemoved;
+5
View File
@@ -205,9 +205,14 @@ proto._invertMask = function () {
};
proto._loadMaskFromURL = function (url) {
const token = this._loadToken; // tie to the image-load generation that requested it
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => {
// bail if a newer open/load superseded this, OR the user already started working
// (painting / has undo history / a painted bbox) - don't clobber fresh strokes.
if (token !== this._loadToken) return;
if (this._painting || this._undo?.length || this._bbox) return;
this._ensureMaskCanvas();
const tmp = document.createElement("canvas");
tmp.width = this.imgW; tmp.height = this.imgH;
+4
View File
@@ -8,9 +8,11 @@ const proto = InpaintCropEditor.prototype;
// ── image load ──────────────────────────────────────────────────────────────
proto._loadImageFromURL = function (url, onDone) {
const token = (this._loadToken = (this._loadToken || 0) + 1); // newest load wins
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => {
if (token !== this._loadToken) return; // a newer open/load superseded this one
this.img = img;
this.imgW = img.naturalWidth;
this.imgH = img.naturalHeight;
@@ -27,8 +29,10 @@ proto._loadImageFromURL = function (url, onDone) {
};
proto._loadImageFromDataURL = function (dataURL) {
const token = (this._loadToken = (this._loadToken || 0) + 1); // newest load wins
const img = new Image();
img.onload = () => {
if (token !== this._loadToken) return; // a newer open/load superseded this one
this.img = img;
this.imgW = img.naturalWidth;
this.imgH = img.naturalHeight;