Initial mostly working multiple splines for SplineEditor

Probably buggy and clumsy to use, but workable and way better than having to use multiple SplineEditors...
This commit is contained in:
kijai 2025-06-03 20:45:08 +03:00
parent 42c7641776
commit ea5482a6ee
2 changed files with 454 additions and 194 deletions

View File

@ -204,47 +204,72 @@ output types:
min_value=0.0, max_value=1.0, bg_image=None): min_value=0.0, max_value=1.0, bg_image=None):
coordinates = json.loads(coordinates) coordinates = json.loads(coordinates)
print("Coordinates: ", coordinates)
# Handle nested list structure if present
all_normalized = []
all_normalized_y_values = []
# Check if we have a nested list structure
if isinstance(coordinates, list) and len(coordinates) > 0 and isinstance(coordinates[0], list):
# Process each list of coordinates in the nested structure
coordinate_sets = coordinates
else:
# If not nested, treat as a single list of coordinates
coordinate_sets = [coordinates]
# Process each set of coordinates
for coord_set in coordinate_sets:
normalized = [] normalized = []
normalized_y_values = [] normalized_y_values = []
for coord in coordinates:
for coord in coord_set:
coord['x'] = int(round(coord['x'])) coord['x'] = int(round(coord['x']))
coord['y'] = int(round(coord['y'])) coord['y'] = int(round(coord['y']))
norm_x = (1.0 - (coord['x'] / mask_height) - 0.0) * (max_value - min_value) + min_value norm_x = (1.0 - (coord['x'] / mask_height) - 0.0) * (max_value - min_value) + min_value
norm_y = (1.0 - (coord['y'] / mask_height) - 0.0) * (max_value - min_value) + min_value norm_y = (1.0 - (coord['y'] / mask_height) - 0.0) * (max_value - min_value) + min_value
normalized_y_values.append(norm_y) normalized_y_values.append(norm_y)
normalized.append({'x':norm_x, 'y':norm_y}) normalized.append({'x':norm_x, 'y':norm_y})
all_normalized.extend(normalized)
all_normalized_y_values.extend(normalized_y_values)
# Use the combined normalized values for output
if float_output_type == 'list': if float_output_type == 'list':
out_floats = normalized_y_values * repeat_output out_floats = all_normalized_y_values * repeat_output
elif float_output_type == 'pandas series': elif float_output_type == 'pandas series':
try: try:
import pandas as pd import pandas as pd
except: except:
raise Exception("MaskOrImageToWeight: pandas is not installed. Please install pandas to use this output_type") raise Exception("MaskOrImageToWeight: pandas is not installed. Please install pandas to use this output_type")
out_floats = pd.Series(normalized_y_values * repeat_output), out_floats = pd.Series(all_normalized_y_values * repeat_output),
elif float_output_type == 'tensor': elif float_output_type == 'tensor':
out_floats = torch.tensor(normalized_y_values * repeat_output, dtype=torch.float32) out_floats = torch.tensor(all_normalized_y_values * repeat_output, dtype=torch.float32)
# Create a color map for grayscale intensities # Create a color map for grayscale intensities
color_map = lambda y: torch.full((mask_height, mask_width, 3), y, dtype=torch.float32) color_map = lambda y: torch.full((mask_height, mask_width, 3), y, dtype=torch.float32)
# Create image tensors for each normalized y value # Create image tensors for each normalized y value
mask_tensors = [color_map(y) for y in normalized_y_values] mask_tensors = [color_map(y) for y in all_normalized_y_values]
masks_out = torch.stack(mask_tensors) masks_out = torch.stack(mask_tensors)
masks_out = masks_out.repeat(repeat_output, 1, 1, 1) masks_out = masks_out.repeat(repeat_output, 1, 1, 1)
masks_out = masks_out.mean(dim=-1) masks_out = masks_out.mean(dim=-1)
if bg_image is None: if bg_image is None:
return (masks_out, json.dumps(coordinates), out_floats, len(out_floats) , json.dumps(normalized)) return (masks_out, json.dumps(coordinates), out_floats, len(out_floats), json.dumps(all_normalized))
else: else:
transform = transforms.ToPILImage() transform = transforms.ToPILImage()
image = transform(bg_image[0].permute(2, 0, 1)) image = transform(bg_image[0].permute(2, 0, 1))
buffered = io.BytesIO() buffered = io.BytesIO()
image.save(buffered, format="JPEG", quality=75) image.save(buffered, format="JPEG", quality=75)
# Step 3: Encode the image bytes to a Base64 string # Encode the image bytes to a Base64 string
img_bytes = buffered.getvalue() img_bytes = buffered.getvalue()
img_base64 = base64.b64encode(img_bytes).decode('utf-8') img_base64 = base64.b64encode(img_bytes).decode('utf-8')
return { return {
"ui": {"bg_image": [img_base64]}, "ui": {"bg_image": [img_base64]},
"result":(masks_out, json.dumps(coordinates), out_floats, len(out_floats) , json.dumps(normalized)) "result": (masks_out, json.dumps(coordinates), out_floats, len(out_floats), json.dumps(all_normalized))
} }

View File

@ -155,6 +155,9 @@ app.registerExtension({
createMenuItem(3, "Background image"), createMenuItem(3, "Background image"),
createMenuItem(4, "Invert point order"), createMenuItem(4, "Invert point order"),
createMenuItem(5, "Clear Image"), createMenuItem(5, "Clear Image"),
createMenuItem(6, "Add new spline"),
createMenuItem(7, "Delete current spline"),
createMenuItem(8, "Next spline"),
]; ];
// Add mouseover and mouseout event listeners to each menu item for styling // Add mouseover and mouseout event listeners to each menu item for styling
@ -175,7 +178,7 @@ app.registerExtension({
document.body.appendChild(this.contextMenu); document.body.appendChild(this.contextMenu);
this.addWidget("button", "New spline", null, () => { this.addWidget("button", "New canvas", null, () => {
if (!this.properties || !("points" in this.properties)) { if (!this.properties || !("points" in this.properties)) {
this.editor = new SplineEditor(this); this.editor = new SplineEditor(this);
this.addProperty("points", this.constructor.type, "string"); this.addProperty("points", this.constructor.type, "string");
@ -341,27 +344,30 @@ this.heightWidget.callback = () => {
this.width = this.widthWidget.value; this.width = this.widthWidget.value;
this.height = this.heightWidget.value; this.height = this.heightWidget.value;
var i = 3; var i = 3;
this.points = []; this.splines = [];
this.activeSplineIndex = 0; // Track which spline is being edited
if (!reset && this.pointsStoreWidget.value != "") { if (!reset && this.pointsStoreWidget.value != "") {
this.points = JSON.parse(this.pointsStoreWidget.value); try {
const parsedData = JSON.parse(this.pointsStoreWidget.value);
// Check if it's already in the new format (array of splines)
if (Array.isArray(parsedData) && parsedData.length > 0 && parsedData[0].hasOwnProperty('points')) {
this.splines = parsedData;
} else { } else {
this.points = pv.range(1, 4).map((i, index) => { // Convert old format (single array of points) to new format
if (index === 0) { this.splines = [{
// First point at the bottom-left corner points: parsedData,
return { x: 0, y: this.height }; color: "#1f77b4",
} else if (index === 2) { name: "Spline 1"
// Last point at the top-right corner }];
return { x: this.width, y: 0 };
} else {
// Other points remain as they were
return {
x: i * this.width / 5,
y: 50 + Math.random() * (this.height - 100)
};
} }
}); } catch (e) {
this.pointsStoreWidget.value = JSON.stringify(this.points); console.error("Error parsing spline data:", e);
this.initializeDefaultSplines();
}
} else {
this.initializeDefaultSplines();
this.pointsStoreWidget.value = JSON.stringify(this.splines);
} }
this.vis = new pv.Panel() this.vis = new pv.Panel()
@ -378,7 +384,7 @@ this.heightWidget.callback = () => {
x: this.mouse().x / app.canvas.ds.scale, x: this.mouse().x / app.canvas.ds.scale,
y: this.mouse().y / app.canvas.ds.scale y: this.mouse().y / app.canvas.ds.scale
}; };
i = self.points.push(scaledMouse) - 1; i = self.splines[self.activeSplineIndex].points.push(scaledMouse) - 1;
self.updatePath(); self.updatePath();
return this; return this;
} }
@ -390,16 +396,17 @@ this.heightWidget.callback = () => {
}; };
// Find the two closest points to the clicked location // Find the two closest points to the clicked location
let { point1Index, point2Index } = self.findClosestPoints(self.points, clickedPoint); const activePoints = self.splines[self.activeSplineIndex].points;
let { point1Index, point2Index } = self.findClosestPoints(self.splines[self.activeSplineIndex].points, clickedPoint);
// Calculate the midpoint between the two closest points // Calculate the midpoint between the two closest points
let midpoint = { let midpoint = {
x: (self.points[point1Index].x + self.points[point2Index].x) / 2, x: (activePoints[point1Index].x + activePoints[point2Index].x) / 2,
y: (self.points[point1Index].y + self.points[point2Index].y) / 2 y: (activePoints[point1Index].y + activePoints[point2Index].y) / 2
}; };
// Insert the midpoint into the array // Insert the midpoint into the array
self.points.splice(point2Index, 0, midpoint); activePoints.splice(point2Index, 0, midpoint);
i = point2Index; i = point2Index;
self.updatePath(); self.updatePath();
} }
@ -418,24 +425,41 @@ this.heightWidget.callback = () => {
.lineWidth(3) .lineWidth(3)
.visible(() => self.drawRuler) .visible(() => self.drawRuler)
// vis.add(pv.Rule) this.hoverSplineIndex = -1;
// .data(pv.range(0, points_to_sample, 1))
// .left(d => d * 512 / (points_to_sample - 1))
// .strokeStyle("gray")
// .lineWidth(2)
this.splines.forEach((spline, splineIndex) => {
this.vis.add(pv.Line) this.vis.add(pv.Line)
.data(() => this.points) .data(() => spline.points)
.left(d => d.x) .left(d => d.x)
.top(d => d.y) .top(d => d.y)
.interpolate(() => this.interpolation) .interpolate(() => this.interpolation)
.tension(() => this.tension) .tension(() => this.tension)
.segmented(() => false) .segmented(() => false)
.strokeStyle(pv.Colors.category10().by(pv.index)) .strokeStyle(spline.color)
.lineWidth(3) .lineWidth(() => {
// Change line width based on active or hover state
if (splineIndex === this.activeSplineIndex) return 3;
if (splineIndex === this.hoverSplineIndex) return 2;
return 1.5;
})
.event("mouseover", () => {
this.hoverSplineIndex = splineIndex;
this.vis.render();
})
.event("mouseout", () => {
this.hoverSplineIndex = -1;
this.vis.render();
})
.event("mousedown", () => {
if (this.activeSplineIndex !== splineIndex) {
this.activeSplineIndex = splineIndex;
this.refreshSplineElements();
}
});
});
this.vis.add(pv.Dot) this.vis.add(pv.Dot)
.data(() => this.points) .data(() => this.splines[this.activeSplineIndex].points)
.left(d => d.x) .left(d => d.x)
.top(d => d.y) .top(d => d.y)
.radius(10) .radius(10)
@ -447,16 +471,17 @@ this.heightWidget.callback = () => {
let angle = 0; let angle = 0;
if (self.dotShape === "triangle") { if (self.dotShape === "triangle") {
const activePoints = self.splines[self.activeSplineIndex].points;
let dxNext = 0, dyNext = 0; let dxNext = 0, dyNext = 0;
if (index < self.points.length - 1) { if (index < activePoints.length - 1) {
dxNext = self.points[index + 1].x - self.points[index].x; dxNext = activePoints[index + 1].x - activePoints[index].x;
dyNext = self.points[index + 1].y - self.points[index].y; dyNext = activePoints[index + 1].y - activePoints[index].y;
} }
let dxPrev = 0, dyPrev = 0; let dxPrev = 0, dyPrev = 0;
if (index > 0) { if (index > 0) {
dxPrev = self.points[index].x - self.points[index - 1].x; dxPrev = activePoints[index].x - activePoints[index - 1].x;
dyPrev = self.points[index].y - self.points[index - 1].y; dyPrev = activePoints[index].y - activePoints[index - 1].y;
} }
const dx = (dxNext + dxPrev) / 2; const dx = (dxNext + dxPrev) / 2;
@ -477,8 +502,9 @@ this.heightWidget.callback = () => {
i = this.index; i = this.index;
hoverIndex = this.index; hoverIndex = this.index;
isDragging = true; isDragging = true;
if (pv.event.button === 2 && i !== 0 && i !== self.points.length - 1) { const activePoints = self.splines[self.activeSplineIndex].points;
self.points.splice(i--, 1); if (pv.event.button === 2 && i !== 0 && i !== activePoints.length - 1) {
activePoints.splice(i--, 1);
self.vis.render(); self.vis.render();
} }
return this; return this;
@ -499,7 +525,7 @@ this.heightWidget.callback = () => {
// Adjust the new position if it would place the dot outside the bounds of the vis.Panel // Adjust the new position if it would place the dot outside the bounds of the vis.Panel
adjustedX = Math.max(0, Math.min(panelWidth, adjustedX)); adjustedX = Math.max(0, Math.min(panelWidth, adjustedX));
adjustedY = Math.max(0, Math.min(panelHeight, adjustedY)); adjustedY = Math.max(0, Math.min(panelHeight, adjustedY));
self.points[this.index] = { x: adjustedX, y: adjustedY }; // Update the point's position self.splines[self.activeSplineIndex].points[this.index] = { x: adjustedX, y: adjustedY }; // Update the point's position
self.vis.render(); // Re-render the visualization to reflect the new position self.vis.render(); // Re-render the visualization to reflect the new position
}) })
.event("mouseover", function() { .event("mouseover", function() {
@ -530,7 +556,7 @@ this.heightWidget.callback = () => {
}) })
.textStyle("orange") .textStyle("orange")
if (this.points.length != 0) { if (this.splines.length != 0) {
this.vis.render(); this.vis.render();
} }
var svgElement = this.vis.canvas(); var svgElement = this.vis.canvas();
@ -548,15 +574,43 @@ this.heightWidget.callback = () => {
} }
updatePath = () => { updatePath = () => {
if (!this.points || this.points.length === 0) { if (!this.splines || this.splines.length === 0) {
console.log("no points"); console.log("no splines");
return; return;
} }
if (this.samplingMethod != "controlpoints") { // Get active spline points
var coords = this.samplePoints(this.pathElements[0], this.points_to_sample, this.samplingMethod, this.width); console.log("this.activeSplineIndex", this.activeSplineIndex);
const activeSpline = this.splines[this.activeSplineIndex];
const activePoints = activeSpline.points;
if (!activePoints || activePoints.length === 0) {
console.log("no points in active spline");
return;
} }
else {
var coords = this.points console.log("this.pathElements", this.pathElements);
let coords;
if (this.samplingMethod != "controlpoints") {
coords = this.samplePoints(this.pathElements[this.activeSplineIndex], this.points_to_sample, this.samplingMethod, this.width, this.activeSplineIndex);
} else {
coords = activePoints;
}
let allSplineCoords = [];
for (let i = 0; i < this.splines.length; i++) {
// Use the same sampling method for all splines
let splineCoords;
const pathElement = this.pathElements[i];
if (this.samplingMethod != "controlpoints" && pathElement) {
splineCoords = this.samplePoints(pathElement, this.points_to_sample, this.samplingMethod, this.width, i);
} else {
// Fall back to control points if no path element or sampling method is "controlpoints"
splineCoords = this.splines[i].points;
}
allSplineCoords.push(splineCoords);
} }
if (this.drawSamplePoints) { if (this.drawSamplePoints) {
@ -581,13 +635,13 @@ this.heightWidget.callback = () => {
this.vis.render(); this.vis.render();
} }
} }
let coordsString = JSON.stringify(coords); this.pointsStoreWidget.value = JSON.stringify(this.splines);
this.pointsStoreWidget.value = JSON.stringify(this.points);
if (this.coordWidget) { if (this.coordWidget) {
this.coordWidget.value = coordsString; this.coordWidget.value = JSON.stringify(allSplineCoords);
} }
this.vis.render(); this.vis.render();
}; };
handleImageLoad = (img, file, base64String) => { handleImageLoad = (img, file, base64String) => {
console.log(img.width, img.height); // Access width and height here console.log(img.width, img.height); // Access width and height here
this.widthWidget.value = img.width; this.widthWidget.value = img.width;
@ -673,11 +727,143 @@ this.heightWidget.callback = () => {
} }
}; };
refreshSplineElements = () => {
// Clear existing line elements and recreate them
const svgElement = this.vis.canvas();
// Remove all existing line elements
const oldLines = svgElement.querySelectorAll('path');
oldLines.forEach(line => line.remove());
this.pathElements = [];
this.lineObjects = [];
const originalChildren = [...this.vis.children];
// Find line objects to remove (those that represent splines)
const linesToRemove = originalChildren.filter(child =>
child instanceof pv.Line
);
linesToRemove.forEach(line => line.visible(false));
// Re-add all spline lines and store references to them
this.splines.forEach((spline, splineIndex) => {
const lineObj = this.vis.add(pv.Line)
.data(() => spline.points)
.left(d => d.x)
.top(d => d.y)
.interpolate(() => this.interpolation)
.tension(() => this.tension)
.segmented(() => false)
.strokeStyle(spline.color)
.lineWidth(() => {
// Change line width based on active or hover state
if (splineIndex === this.activeSplineIndex) return 3;
if (splineIndex === this.hoverSplineIndex) return 2;
return 1.5;
})
.event("mouseover", () => {
this.hoverSplineIndex = splineIndex;
this.vis.render();
})
.event("mouseout", () => {
this.hoverSplineIndex = -1;
this.vis.render();
})
.event("mousedown", () => {
if (this.activeSplineIndex !== splineIndex) {
this.activeSplineIndex = splineIndex;
this.refreshSplineElements();
}
});
this.lineObjects.push(lineObj);
});
this.vis.render();
requestAnimationFrame(() => {
const allPaths = Array.from(svgElement.querySelectorAll('path'));
this.pathElements = [];
// First try: look at paths with specific childIndex values
this.lineObjects.forEach((lineObj, i) => {
// Find paths that correspond to our line objects
const childIndex = lineObj.childIndex;
const matchingPath = allPaths.find(path =>
path.$scene && path.$scene.scenes &&
path.$scene.scenes.childIndex === childIndex
);
if (matchingPath) {
console.log("matchingPath:", matchingPath);
this.pathElements[i] = matchingPath;
}
});
// Check if we found all paths
if (this.pathElements.filter(p => p).length !== this.splines.length) {
// Fallback to color matching
this.pathElements = [];
for (let i = 0; i < this.splines.length; i++) {
const color = this.splines[i].color;
const matchingPath = allPaths.find(p =>
p.getAttribute('style')?.includes(color) &&
!this.pathElements.includes(p)
);
if (matchingPath) {
this.pathElements[i] = matchingPath;
}
}
}
// If we still don't have the right number of paths, use the first N paths
if (this.pathElements.filter(p => p).length !== this.splines.length) {
this.pathElements = allPaths.slice(0, this.splines.length);
}
this.updatePath();
});
};
initializeDefaultSplines() {
this.splines = [{
points: pv.range(1, 4).map((i, index) => {
if (index === 0) {
return { x: 0, y: this.height };
} else if (index === 2) {
return { x: this.width, y: 0 };
} else {
return {
x: i * this.width / 5,
y: 50 + Math.random() * (this.height - 100)
};
}
}),
color: this.getSplineColor(0),
name: "Spline 1"
}];
}
getSplineColor(index) {
const colors = [
"#1f77b4", "#ff7f0e", "#2ca02c", "#d62728",
"#9467bd", "#8c564b", "#e377c2", "#7f7f7f",
"#bcbd22", "#17becf"
];
return colors[index % colors.length];
}
createContextMenu = () => { createContextMenu = () => {
self = this; const self = this;
const oldMenu = this.node.contextMenu;
const newMenu = oldMenu.cloneNode(true);
oldMenu.parentNode.replaceChild(newMenu, oldMenu);
this.node.contextMenu = newMenu;
document.addEventListener('contextmenu', function (e) { document.addEventListener('contextmenu', function (e) {
e.preventDefault(); e.preventDefault();
}); });
document.addEventListener('click', function (e) { document.addEventListener('click', function (e) {
@ -686,17 +872,18 @@ this.heightWidget.callback = () => {
}); });
}); });
this.node.menuItems.forEach((menuItem, index) => { this.node.contextMenu.addEventListener('click', function(e) {
self = this;
menuItem.addEventListener('click', function (e) {
e.preventDefault(); e.preventDefault();
switch (index) { if (e.target.tagName === 'A') {
const id = parseInt(e.target.id.split('-')[2]);
switch(id) {
case 0: case 0:
e.preventDefault(); e.preventDefault();
if (!self.drawHandles) { if (!self.drawHandles) {
self.drawHandles = true self.drawHandles = true
self.vis.add(pv.Line) self.vis.add(pv.Line)
.data(() => self.points.map((point, index) => ({ .data(() => self.splines[self.activeSplineIndex].points.map((point, index) => ({
start: point, start: point,
end: [index] end: [index]
}))) })))
@ -715,12 +902,11 @@ this.heightWidget.callback = () => {
self.node.contextMenu.style.display = 'none'; self.node.contextMenu.style.display = 'none';
break; break;
case 1: case 1:
e.preventDefault();
self.drawSamplePoints = !self.drawSamplePoints; self.drawSamplePoints = !self.drawSamplePoints;
self.updatePath(); self.updatePath();
break; break;
case 2: case 2:
e.preventDefault();
if (self.dotShape == "circle"){ if (self.dotShape == "circle"){
self.dotShape = "triangle" self.dotShape = "triangle"
} }
@ -753,8 +939,7 @@ this.heightWidget.callback = () => {
self.node.contextMenu.style.display = 'none'; self.node.contextMenu.style.display = 'none';
break; break;
case 4: case 4:
e.preventDefault(); self.splines[self.activeSplineIndex].points.reverse();
self.points.reverse();
self.updatePath(); self.updatePath();
break; break;
case 5: case 5:
@ -762,14 +947,73 @@ this.heightWidget.callback = () => {
self.node.properties.imgData = null; self.node.properties.imgData = null;
self.node.contextMenu.style.display = 'none'; self.node.contextMenu.style.display = 'none';
break; break;
} case 6: // Add new spline
const newSplineIndex = self.splines.length;
self.splines.push({
points: [
// Create default points for the new spline
{ x: 0, y: self.height },
{ x: self.width/2, y: self.height/2 },
{ x: self.width, y: 0 }
],
color: self.getSplineColor(newSplineIndex),
name: `Spline ${newSplineIndex + 1}`
}); });
self.activeSplineIndex = newSplineIndex;
self.refreshSplineElements();
self.node.contextMenu.style.display = 'none';
break;
case 7: // Delete current spline
if (self.splines.length > 1) {
self.splines.splice(self.activeSplineIndex, 1);
self.activeSplineIndex = Math.min(self.activeSplineIndex, self.splines.length - 1);
self.refreshSplineElements();
}
self.node.contextMenu.style.display = 'none';
break;
case 8: // Next spline
self.activeSplineIndex = (self.activeSplineIndex + 1) % self.splines.length;
self.refreshSplineElements();
self.node.contextMenu.style.display = 'none';
break;
}
}
}); });
} }
samplePoints(svgPathElement, numSamples, samplingMethod, width) { samplePoints(svgPathElement, numSamples, samplingMethod, width, splineIndex) {
if (!svgPathElement) {
console.warn(`Path element not found for spline index: ${splineIndex}. Available paths: ${this.pathElements.length}`);
const splinePoints = this.splines[splineIndex].points;
// If we have no points, return an empty array
if (!splinePoints || splinePoints.length === 0) {
return [];
}
// Create a simple interpolation between control points
const result = [];
for (let i = 0; i < numSamples; i++) {
const t = i / (numSamples - 1);
const idx = Math.min(
Math.floor(t * (splinePoints.length - 1)),
splinePoints.length - 2
);
const fraction = (t * (splinePoints.length - 1)) - idx;
const x = splinePoints[idx].x + fraction * (splinePoints[idx + 1].x - splinePoints[idx].x);
const y = splinePoints[idx].y + fraction * (splinePoints[idx + 1].y - splinePoints[idx].y);
result.push({ x, y });
}
return result;
}
var svgWidth = width; // Fixed width of the SVG element var svgWidth = width; // Fixed width of the SVG element
var pathLength = svgPathElement.getTotalLength(); var pathLength = svgPathElement.getTotalLength();
console.log(" pathLength:", pathLength);
var points = []; var points = [];
for (var i = 0; i < numSamples; i++) { for (var i = 0; i < numSamples; i++) {
@ -846,16 +1090,7 @@ export function hideWidgetForGood(node, widget, suffix = '') {
widget.origSerializeValue = widget.serializeValue widget.origSerializeValue = widget.serializeValue
widget.computeSize = () => [0, -4] // -4 is due to the gap litegraph adds between widgets automatically widget.computeSize = () => [0, -4] // -4 is due to the gap litegraph adds between widgets automatically
widget.type = "converted-widget" + suffix widget.type = "converted-widget" + suffix
// widget.serializeValue = () => {
// // Prevent serializing the widget if we have no input linked
// const w = node.inputs?.find((i) => i.widget?.name === widget.name);
// if (w?.link == null) {
// return undefined;
// }
// return widget.origSerializeValue ? widget.origSerializeValue() : widget.value;
// };
// Hide any linked widgets, e.g. seed+seedControl
if (widget.linkedWidgets) { if (widget.linkedWidgets) {
for (const w of widget.linkedWidgets) { for (const w of widget.linkedWidgets) {
hideWidgetForGood(node, w, ':' + widget.name) hideWidgetForGood(node, w, ':' + widget.name)