From 8eab69fa71310c5043d7a5e9a26a5f10730db82b Mon Sep 17 00:00:00 2001 From: cho Date: Sun, 7 Apr 2024 22:22:34 -0700 Subject: [PATCH 1/5] snap group to grid if SHIFT is down or "always snap to grid" is enabled --- web/js/snapToGrid.js | 81 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/web/js/snapToGrid.js b/web/js/snapToGrid.js index 6cdc318..452ace2 100644 --- a/web/js/snapToGrid.js +++ b/web/js/snapToGrid.js @@ -52,6 +52,87 @@ const ext = { return configure.apply(this, arguments); }; + + // keep states related to the drag-and-drop of groups + let dndState = { + group: null, + ctrlDown: false, + }; + + // when ctrl is pressed, we default to the original behavior of smooth translation w/o affecting the nodes in the group + window.addEventListener("keydown", (e) => { + // check whether ctrl is pressed + if (e.ctrlKey) { + dndState.ctrlDown = true; + } + }); + + window.addEventListener("keyup", (e) => { + // check whether ctrl is released + if (!e.ctrlKey) { + dndState.ctrlDown = false; + } + }); + + // capture the drag-and-drop event for groups + const onMouseDown = LGraphCanvas.prototype.onMouseDown; + LGraphCanvas.prototype.onMouseDown = function (e) { + const r = onMouseDown?.apply(this, arguments); + const group = this.graph.getGroupOnPos(this.graph_mouse[0], this.graph_mouse[1]); + dndState.group = group; + dndState.origMouseX = this.graph_mouse[0]; + dndState.origMouseY = this.graph_mouse[1]; + return r; + }; + + const onMouseUp = LGraphCanvas.prototype.onMouseUp; + LGraphCanvas.prototype.onMouseUp = function (e) { + const r = onMouseUp?.apply(this, arguments); + dndState.group = null; + return r; + }; + + // override the drawGroups function to snap the group to the grid + const origDrawGroups = LGraphCanvas.prototype.drawGroups; + LGraphCanvas.prototype.drawGroups = function () { + const snapToGrid = app.shiftDown || setting?.value; + const mouseX = this.graph_mouse[0]; + const mouseY = this.graph_mouse[1]; + let shiftX = 0; + let shiftY = 0; + if (snapToGrid && !dndState.ctrlDown && dndState.group) { + // discretize the canvas position to the nearest snappable coordinate, + // but account for the diff between mouse and group positions + const g = dndState.group; + shiftX = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseX - g.pos[0]) / LiteGraph.CANVAS_GRID_SIZE); + shiftY = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseY - g.pos[1]) / LiteGraph.CANVAS_GRID_SIZE); + + let x = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseX) / LiteGraph.CANVAS_GRID_SIZE); + let y = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseY) / LiteGraph.CANVAS_GRID_SIZE); + x -= shiftX; + y -= shiftY; + + // update group position (`move()` does not yield smooth translation across canvas) + const dx = g.pos[0] - x; + const dy = g.pos[1] - y; + g.pos[0] = x; + g.pos[1] = y; + + // translate all nodes in group, translate them by dx, dy + for (const node of g._nodes) { + node.pos[0] -= dx; + node.pos[1] -= dy; + } + + // ensure the group bounds are snapped to the grid (e.g., when resizing the group) + // caveat: this may resize the group to snap the bounds to the grid, even if the group is not being resized but only being moved + g.size[0] = LiteGraph.CANVAS_GRID_SIZE * Math.round(g.size[0] / LiteGraph.CANVAS_GRID_SIZE); + g.size[1] = LiteGraph.CANVAS_GRID_SIZE * Math.round(g.size[1] / LiteGraph.CANVAS_GRID_SIZE); + + } + + return origDrawGroups.apply(this, arguments); + }; }, }; From 7569dc2796d87796c27facec63b65ed23e8d67fa Mon Sep 17 00:00:00 2001 From: cho Date: Sun, 7 Apr 2024 22:32:03 -0700 Subject: [PATCH 2/5] holding down CTRL prevents nodes from moving but should not disable group snapping --- web/js/snapToGrid.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/web/js/snapToGrid.js b/web/js/snapToGrid.js index 452ace2..b7c87cf 100644 --- a/web/js/snapToGrid.js +++ b/web/js/snapToGrid.js @@ -100,7 +100,7 @@ const ext = { const mouseY = this.graph_mouse[1]; let shiftX = 0; let shiftY = 0; - if (snapToGrid && !dndState.ctrlDown && dndState.group) { + if (snapToGrid && dndState.group) { // discretize the canvas position to the nearest snappable coordinate, // but account for the diff between mouse and group positions const g = dndState.group; @@ -119,9 +119,12 @@ const ext = { g.pos[1] = y; // translate all nodes in group, translate them by dx, dy - for (const node of g._nodes) { - node.pos[0] -= dx; - node.pos[1] -= dy; + // but don't do this when ctrl is pressed + if (!dndState.ctrlDown) { + for (const node of g._nodes) { + node.pos[0] -= dx; + node.pos[1] -= dy; + } } // ensure the group bounds are snapped to the grid (e.g., when resizing the group) From 4e1ec0f92cc0b8ea51163631517d1e71b4ab0320 Mon Sep 17 00:00:00 2001 From: cho Date: Sun, 7 Apr 2024 22:46:11 -0700 Subject: [PATCH 3/5] remove unused states --- web/js/snapToGrid.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/web/js/snapToGrid.js b/web/js/snapToGrid.js index b7c87cf..512a2fa 100644 --- a/web/js/snapToGrid.js +++ b/web/js/snapToGrid.js @@ -80,8 +80,6 @@ const ext = { const r = onMouseDown?.apply(this, arguments); const group = this.graph.getGroupOnPos(this.graph_mouse[0], this.graph_mouse[1]); dndState.group = group; - dndState.origMouseX = this.graph_mouse[0]; - dndState.origMouseY = this.graph_mouse[1]; return r; }; From efa78b7375f1914ce5093bcadafc2234de7ba498 Mon Sep 17 00:00:00 2001 From: cho Date: Sun, 7 Apr 2024 23:31:27 -0700 Subject: [PATCH 4/5] smoother group resizing when snapping to grid --- web/js/snapToGrid.js | 58 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/web/js/snapToGrid.js b/web/js/snapToGrid.js index 512a2fa..30944f8 100644 --- a/web/js/snapToGrid.js +++ b/web/js/snapToGrid.js @@ -102,34 +102,40 @@ const ext = { // discretize the canvas position to the nearest snappable coordinate, // but account for the diff between mouse and group positions const g = dndState.group; - shiftX = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseX - g.pos[0]) / LiteGraph.CANVAS_GRID_SIZE); - shiftY = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseY - g.pos[1]) / LiteGraph.CANVAS_GRID_SIZE); - let x = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseX) / LiteGraph.CANVAS_GRID_SIZE); - let y = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseY) / LiteGraph.CANVAS_GRID_SIZE); - x -= shiftX; - y -= shiftY; - - // update group position (`move()` does not yield smooth translation across canvas) - const dx = g.pos[0] - x; - const dy = g.pos[1] - y; - g.pos[0] = x; - g.pos[1] = y; - - // translate all nodes in group, translate them by dx, dy - // but don't do this when ctrl is pressed - if (!dndState.ctrlDown) { - for (const node of g._nodes) { - node.pos[0] -= dx; - node.pos[1] -= dy; - } + if (this.selected_group_resizing) { + // snap after redrawing the group during a resize, to avoid flickering title bar + // TODO: show preview box like we do for nodes + const r = origDrawGroups.apply(this, arguments); + // ensure the group bounds are snapped to the grid (e.g., when resizing the group) + g.size[0] = LiteGraph.CANVAS_GRID_SIZE * Math.round(g.size[0] / LiteGraph.CANVAS_GRID_SIZE); + g.size[1] = LiteGraph.CANVAS_GRID_SIZE * Math.round(g.size[1] / LiteGraph.CANVAS_GRID_SIZE); + return r; + } else { + // unlike resizing, we snap the group and its nodes before redrawing, to avoid flickering + shiftX = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseX - g.pos[0]) / LiteGraph.CANVAS_GRID_SIZE); + shiftY = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseY - g.pos[1]) / LiteGraph.CANVAS_GRID_SIZE); + + let x = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseX) / LiteGraph.CANVAS_GRID_SIZE); + let y = LiteGraph.CANVAS_GRID_SIZE * Math.round((mouseY) / LiteGraph.CANVAS_GRID_SIZE); + x -= shiftX; + y -= shiftY; + + // update group position (`move()` does not yield smooth translation across canvas) + const dx = g.pos[0] - x; + const dy = g.pos[1] - y; + g.pos[0] = x; + g.pos[1] = y; + + // translate all nodes in group, translate them by dx, dy + // but don't do this when ctrl is pressed + if (!dndState.ctrlDown) { + for (const node of g._nodes) { + node.pos[0] -= dx; + node.pos[1] -= dy; + } + } } - - // ensure the group bounds are snapped to the grid (e.g., when resizing the group) - // caveat: this may resize the group to snap the bounds to the grid, even if the group is not being resized but only being moved - g.size[0] = LiteGraph.CANVAS_GRID_SIZE * Math.round(g.size[0] / LiteGraph.CANVAS_GRID_SIZE); - g.size[1] = LiteGraph.CANVAS_GRID_SIZE * Math.round(g.size[1] / LiteGraph.CANVAS_GRID_SIZE); - } return origDrawGroups.apply(this, arguments); From e6dff647a87cf3f20569d4e5d2e41567a1ea925c Mon Sep 17 00:00:00 2001 From: cho Date: Mon, 8 Apr 2024 20:03:57 -0700 Subject: [PATCH 5/5] comment change only --- web/js/moveSelection.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 web/js/moveSelection.js diff --git a/web/js/moveSelection.js b/web/js/moveSelection.js new file mode 100644 index 0000000..8352db2 --- /dev/null +++ b/web/js/moveSelection.js @@ -0,0 +1,17 @@ +import { app } from "../../../scripts/app.js"; + +let setting; +const id = "pysssss.MoveSelection"; +const ext = { + name: id, + init() { + setting = app.ui.settings.addSetting({ + id, + name: "🐍 Always move selected nodes (without SHIFT)", + defaultValue: false, + type: "boolean", + }); + }, +}; + +app.registerExtension(ext);