Added ability to lock nodes + groups from moving/resizing
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
Adds Lock/Unlock menu item to node/edit group to prevent moving/resizing
|
||||
|
||||
|
||||
|
||||
hacky code in here
|
||||
@@ -0,0 +1,154 @@
|
||||
import { api } from "/scripts/api.js";
|
||||
import { app } from "/scripts/app.js";
|
||||
|
||||
// Simple script that adds the current queue size to the window title
|
||||
// Adds a favicon that changes color while active
|
||||
|
||||
const LOCKED = Symbol();
|
||||
|
||||
function lockArray(arr, isLocked) {
|
||||
const v = [];
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
v[i] = arr[i];
|
||||
|
||||
Object.defineProperty(arr, i, {
|
||||
get() {
|
||||
return v[i];
|
||||
},
|
||||
set(value) {
|
||||
if (!isLocked()) {
|
||||
v[i] = value;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: "pysssss.Locking",
|
||||
init() {
|
||||
function lockGroup(node) {
|
||||
// Store the original move and nop it
|
||||
node[LOCKED] = node.move;
|
||||
node.move = () => {};
|
||||
|
||||
// Hack to prevent resizing
|
||||
// size isnt a configurable property and there is no resize event
|
||||
// _size is an arraybuffer, so we cant prevent setting that either
|
||||
// replace it with an array and prevent setting the 0/1 indexes
|
||||
node._size = [node._size[0], node._size[1]];
|
||||
lockArray(node._size, () => !!node[LOCKED]);
|
||||
}
|
||||
|
||||
// Add the locked flag to serialization
|
||||
const serialize = LGraphGroup.prototype.serialize;
|
||||
LGraphGroup.prototype.serialize = function () {
|
||||
const o = serialize.apply(this, arguments);
|
||||
o.locked = !!this[LOCKED];
|
||||
return o;
|
||||
};
|
||||
|
||||
// On initial configure lock group if required
|
||||
const configure = LGraphGroup.prototype.configure;
|
||||
LGraphGroup.prototype.configure = function (o) {
|
||||
configure.apply(this, arguments);
|
||||
if (o.locked) {
|
||||
lockGroup(this);
|
||||
}
|
||||
};
|
||||
|
||||
// Add menu options for lock/unlock
|
||||
const getGroupMenuOptions = LGraphCanvas.prototype.getGroupMenuOptions;
|
||||
LGraphCanvas.prototype.getGroupMenuOptions = function (node) {
|
||||
const opts = getGroupMenuOptions.apply(this, arguments);
|
||||
|
||||
opts.unshift(
|
||||
node[LOCKED]
|
||||
? {
|
||||
content: "Unlock",
|
||||
callback: () => {
|
||||
node.move = node[LOCKED];
|
||||
delete node[LOCKED];
|
||||
},
|
||||
}
|
||||
: {
|
||||
content: "Lock",
|
||||
callback: () => lockGroup(node),
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
return opts;
|
||||
};
|
||||
},
|
||||
async beforeRegisterNodeDef(nodeType) {
|
||||
function lockNode(node) {
|
||||
node[LOCKED] = true;
|
||||
// Same hack as above
|
||||
lockArray(node.pos, () => !!node[LOCKED]);
|
||||
|
||||
// Size is set by both replacing the value and setting individual values
|
||||
// So define a new property that can prevent reassignment
|
||||
const sz = [node.size[0], node.size[1]];
|
||||
Object.defineProperty(node, "size", {
|
||||
get() {
|
||||
return sz;
|
||||
},
|
||||
set(value) {
|
||||
if (!node[LOCKED]) {
|
||||
sz[0] = value[0];
|
||||
sz[1] = value[1];
|
||||
}
|
||||
},
|
||||
});
|
||||
// And then lock each element if required
|
||||
lockArray(sz, () => !!node[LOCKED]);
|
||||
}
|
||||
|
||||
// Add menu options for lock/unlock
|
||||
const getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function (_, options) {
|
||||
const r = getExtraMenuOptions ? getExtraMenuOptions.apply(this, arguments) : undefined;
|
||||
|
||||
options.splice(
|
||||
options.findIndex((o) => o?.content === "Properties") + 1,
|
||||
0,
|
||||
null,
|
||||
this[LOCKED]
|
||||
? {
|
||||
content: "Unlock",
|
||||
callback: () => {
|
||||
delete this[LOCKED];
|
||||
},
|
||||
}
|
||||
: {
|
||||
content: "Lock",
|
||||
callback: () => lockNode(this),
|
||||
}
|
||||
);
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
// Add the locked flag to serialization
|
||||
const onSerialize = nodeType.prototype.onSerialize;
|
||||
nodeType.prototype.onSerialize = function (o) {
|
||||
if (onSerialize) {
|
||||
onSerialize.apply(this, arguments);
|
||||
}
|
||||
o.locked = this[LOCKED];
|
||||
};
|
||||
|
||||
// On initial configure lock node if required
|
||||
const onConfigure = nodeType.prototype.onConfigure;
|
||||
nodeType.prototype.onConfigure = function (o) {
|
||||
if (onConfigure) {
|
||||
onConfigure.apply(this, arguments);
|
||||
}
|
||||
if (o.locked) {
|
||||
lockNode(this);
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user