|
import { app } from "../../../scripts/app.js";
|
|
import { $el } from "../../../scripts/ui.js";
|
|
|
|
let setting, guide_setting, guide_config;
|
|
const id = "pysssss.SnapToGrid";
|
|
const guide_id = id + ".Guide";
|
|
const guide_config_default = {
|
|
lines: {
|
|
enabled: false,
|
|
fillStyle: "rgba(255, 0, 0, 0.5)",
|
|
},
|
|
block: {
|
|
enabled: false,
|
|
fillStyle: "rgba(0, 0, 255, 0.5)",
|
|
},
|
|
}
|
|
|
|
|
|
function wrapCallInSettingCheck(fn) {
|
|
if (setting?.value) {
|
|
const shift = app.shiftDown;
|
|
app.shiftDown = true;
|
|
const r = fn();
|
|
app.shiftDown = shift;
|
|
return r;
|
|
}
|
|
return fn();
|
|
}
|
|
|
|
const ext = {
|
|
name: id,
|
|
init() {
|
|
if (localStorage.getItem(guide_id) === null) {
|
|
localStorage.setItem(guide_id, JSON.stringify(guide_config_default));
|
|
}
|
|
guide_config = JSON.parse(localStorage.getItem(guide_id));
|
|
|
|
setting = app.ui.settings.addSetting({
|
|
id,
|
|
name: "🐍 Always snap to grid",
|
|
defaultValue: false,
|
|
type: "boolean",
|
|
onChange(value) {
|
|
app.canvas.align_to_grid = value;
|
|
},
|
|
});
|
|
|
|
guide_setting = app.ui.settings.addSetting({
|
|
id: id + ".Guide",
|
|
name: "🐍 Display drag-and-drop guides",
|
|
type: (name, setter, value) => {
|
|
return $el("tr", [
|
|
$el("td", [
|
|
$el("label", {
|
|
for: id.replaceAll(".", "-"),
|
|
textContent: name,
|
|
}),
|
|
]),
|
|
$el("td", [
|
|
$el(
|
|
"label",
|
|
{
|
|
textContent: "Lines: ",
|
|
style: {
|
|
display: "inline-block",
|
|
},
|
|
},
|
|
[
|
|
$el("input", {
|
|
id: id.replaceAll(".", "-") + "-line-text",
|
|
type: "text",
|
|
value: guide_config.lines.fillStyle,
|
|
onchange: (event) => {
|
|
guide_config.lines.fillStyle = event.target.value;
|
|
localStorage.setItem(guide_id, JSON.stringify(guide_config));
|
|
}
|
|
}),
|
|
$el("input", {
|
|
id: id.replaceAll(".", "-") + "-line-checkbox",
|
|
type: "checkbox",
|
|
checked: guide_config.lines.enabled,
|
|
onchange: (event) => {
|
|
guide_config.lines.enabled = !!event.target.checked;
|
|
localStorage.setItem(guide_id, JSON.stringify(guide_config));
|
|
},
|
|
}),
|
|
]
|
|
),
|
|
$el(
|
|
"label",
|
|
{
|
|
textContent: "Block: ",
|
|
style: {
|
|
display: "inline-block",
|
|
},
|
|
},
|
|
[
|
|
$el("input", {
|
|
id: id.replaceAll(".", "-") + "-block-text",
|
|
type: "text",
|
|
value: guide_config.block.fillStyle,
|
|
onchange: (event) => {
|
|
guide_config.block.fillStyle = event.target.value;
|
|
localStorage.setItem(guide_id, JSON.stringify(guide_config));
|
|
}
|
|
}),
|
|
$el("input", {
|
|
id: id.replaceAll(".", "-") + '-block-checkbox',
|
|
type: "checkbox",
|
|
checked: guide_config.block.enabled,
|
|
onchange: (event) => {
|
|
guide_config.block.enabled = !!event.target.checked;
|
|
localStorage.setItem(guide_id, JSON.stringify(guide_config));
|
|
},
|
|
}),
|
|
]
|
|
),
|
|
]),
|
|
]);
|
|
}
|
|
});
|
|
|
|
|
|
|
|
const configure = LGraph.prototype.configure;
|
|
LGraph.prototype.configure = function () {
|
|
|
|
const drawNode = LGraphCanvas.prototype.drawNode;
|
|
LGraphCanvas.prototype.drawNode = function () {
|
|
wrapCallInSettingCheck(() => drawNode.apply(this, arguments));
|
|
};
|
|
|
|
|
|
const onNodeAdded = app.graph.onNodeAdded;
|
|
app.graph.onNodeAdded = function (node) {
|
|
const r = onNodeAdded?.apply(this, arguments);
|
|
const onResize = node.onResize;
|
|
node.onResize = function () {
|
|
wrapCallInSettingCheck(() => onResize?.apply(this, arguments));
|
|
};
|
|
return r;
|
|
};
|
|
|
|
|
|
const groupMove = LGraphGroup.prototype.move;
|
|
LGraphGroup.prototype.move = function(deltax, deltay, ignore_nodes) {
|
|
wrapCallInSettingCheck(() => groupMove.apply(this, arguments));
|
|
}
|
|
|
|
const canvasDrawGroups = LGraphCanvas.prototype.drawGroups;
|
|
LGraphCanvas.prototype.drawGroups = function (canvas, ctx) {
|
|
wrapCallInSettingCheck(() => canvasDrawGroups.apply(this, arguments));
|
|
}
|
|
|
|
const canvasOnGroupAdd = LGraphCanvas.onGroupAdd;
|
|
LGraphCanvas.onGroupAdd = function() {
|
|
wrapCallInSettingCheck(() => canvasOnGroupAdd.apply(this, arguments));
|
|
}
|
|
|
|
return configure.apply(this, arguments);
|
|
};
|
|
|
|
|
|
const origDrawNode = LGraphCanvas.prototype.drawNode
|
|
LGraphCanvas.prototype.drawNode = function (node, ctx) {
|
|
const enabled = guide_config.lines.enabled || guide_config.block.enabled;
|
|
if (enabled && app.shiftDown && this.node_dragged && node.id in this.selected_nodes) {
|
|
|
|
let x = LiteGraph.CANVAS_GRID_SIZE * Math.round(node.pos[0] / LiteGraph.CANVAS_GRID_SIZE);
|
|
let y = LiteGraph.CANVAS_GRID_SIZE * Math.round(node.pos[1] / LiteGraph.CANVAS_GRID_SIZE);
|
|
|
|
|
|
|
|
x -= node.pos[0];
|
|
y -= node.pos[1];
|
|
let w, h;
|
|
if (node.flags.collapsed) {
|
|
w = node._collapsed_width;
|
|
h = LiteGraph.NODE_TITLE_HEIGHT;
|
|
y -= LiteGraph.NODE_TITLE_HEIGHT;
|
|
} else {
|
|
w = node.size[0];
|
|
h = node.size[1];
|
|
let titleMode = node.constructor.title_mode;
|
|
if (titleMode !== LiteGraph.TRANSPARENT_TITLE && titleMode !== LiteGraph.NO_TITLE) {
|
|
h += LiteGraph.NODE_TITLE_HEIGHT;
|
|
y -= LiteGraph.NODE_TITLE_HEIGHT;
|
|
}
|
|
}
|
|
|
|
|
|
const f = ctx.fillStyle;
|
|
|
|
|
|
if (guide_config.block.enabled) {
|
|
ctx.fillStyle = guide_config.block.fillStyle;
|
|
ctx.fillRect(x, y, w, h);
|
|
}
|
|
|
|
|
|
if (guide_config.lines.enabled) {
|
|
const xd = 10000;
|
|
const yd = 10000;
|
|
const thickness = 3;
|
|
ctx.fillStyle = guide_config.lines.fillStyle;
|
|
ctx.fillRect(x - xd, y, 2*xd, thickness);
|
|
ctx.fillRect(x, y - yd, thickness, 2*yd);
|
|
ctx.fillRect(x - xd, y + h, 2*xd, thickness);
|
|
ctx.fillRect(x + w, y - yd, thickness, 2*yd);
|
|
}
|
|
|
|
|
|
ctx.fillStyle = f;
|
|
}
|
|
|
|
return origDrawNode.apply(this, arguments);
|
|
};
|
|
},
|
|
};
|
|
|
|
app.registerExtension(ext);
|
|
|