Merge remote-tracking branch 'origin/main' into fix/resize-selected-together
This commit is contained in:
@@ -9,6 +9,10 @@ All notable changes to ComfyUI-AusBoss are documented here.
|
||||
get its width, nodes side by side in a row get its height, and a grid gets
|
||||
both. It works in the classic look and in Nodes 2.0, one Ctrl+Z undoes it,
|
||||
and Settings → 🆎 AusBoss → Canvas → Resize together turns it off.
|
||||
- **Integer 🆎 and Float 🆎 have a big look.** The gear on the node picks it,
|
||||
as on Text 🆎: one large number in the middle of the node, for a setting
|
||||
you change on every run. The value and what the node sends are the same in
|
||||
both looks.
|
||||
- **New node: H3 Prompt Writer.** Type one line for each thing that happens,
|
||||
give each picture and video a job, and it writes the prompt MiniMax H3
|
||||
expects, with the width and height to match. For a video with two people,
|
||||
|
||||
@@ -8,6 +8,11 @@ every node that needs it, and change it in one place.
|
||||
- **Value** (`value`): The number to send out. It starts at `0`. The box
|
||||
shows the decimals its steps use (`0.00`) and holds up to three, so a
|
||||
typed `0.125` stays `0.125`.
|
||||
- The gear, right: **Look**. **normal** is the usual box with its label.
|
||||
**big** shows the number large in the middle of the node, with an arrow
|
||||
on each side, for a setting people change on every run, such as the
|
||||
length of a clip. A drag and typing work the same. Each node keeps its own look, and it is
|
||||
saved with the workflow.
|
||||
|
||||
## Limits
|
||||
|
||||
@@ -44,3 +49,7 @@ into **Math Expression 🆎** instead of retyping derived numbers.
|
||||
API is passed on as it is.
|
||||
- Wired only to inputs that share no value (one stops at 1, the other starts
|
||||
at 2), the box keeps no limits.
|
||||
- The look is stored in the node's properties as `ausboss_text_look: "big"`, the
|
||||
same as Text 🆎. It is not an input, so the saved value and what the node
|
||||
sends are the same in both looks, and an older version of the pack shows
|
||||
the usual box.
|
||||
|
||||
@@ -8,6 +8,11 @@ wire it to every node that needs it.
|
||||
- **Value** (`value`): The whole number to send out. It starts at `0`. The
|
||||
arrows and a drag move it by 1, or click and type. It holds numbers as
|
||||
big as a seed.
|
||||
- The gear, right: **Look**. **normal** is the usual box with its label.
|
||||
**big** shows the number large in the middle of the node, with an arrow
|
||||
on each side, for a setting people change on every run, such as the
|
||||
length of a clip. A drag and typing work the same. Each node keeps its own look, and it is
|
||||
saved with the workflow.
|
||||
|
||||
## Limits
|
||||
|
||||
@@ -40,3 +45,7 @@ For arithmetic on the way — halving a size, adding a margin — feed this into
|
||||
- On its own the box goes up to 9,007,199,254,740,991, the largest whole
|
||||
number a browser holds exactly. It stopped at 2,147,483,647 before, which
|
||||
most seeds are above.
|
||||
- The look is stored in the node's properties as `ausboss_text_look: "big"`, the
|
||||
same as Text 🆎. It is not an input, so the saved value and what the node
|
||||
sends are the same in both looks, and an older version of the pack shows
|
||||
the usual box.
|
||||
|
||||
+15
-1
@@ -1,6 +1,8 @@
|
||||
// The Text node's two looks, chosen per node from the gear on its card: the
|
||||
// usual text box (the default), or "big", a word or two in large centred
|
||||
// letters that are easy to spot, for a label typed over a picture.
|
||||
// letters that are easy to spot, for a label typed over a picture. Integer
|
||||
// and Float take the same two looks, kept in the same property: big is one
|
||||
// large centred number, for a setting people change on every run.
|
||||
//
|
||||
// The choice is kept in the node's properties, so it is saved with the
|
||||
// workflow and nothing else changes: the node's inputs, its saved widget
|
||||
@@ -47,6 +49,18 @@ export const TEXT_LOOK_MENU = [
|
||||
},
|
||||
];
|
||||
|
||||
// The same choice on Integer and Float, said for a number.
|
||||
export const NUMBER_LOOK_MENU = [
|
||||
{
|
||||
...TEXT_LOOK_MENU[0],
|
||||
hint: "How this box shows its number. Stored on this node.",
|
||||
optionHints: {
|
||||
normal: "the usual number box with its label.",
|
||||
big: "one large centred number, for a setting you change on every run.",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// Room the gear takes from the card's control column. The usual box keeps
|
||||
// the gear beside it; the big field spans the card and the gear sits in its
|
||||
// top corner instead.
|
||||
|
||||
@@ -68,6 +68,10 @@ const BIG_FONT = 22;
|
||||
const BIG_LINE = 26;
|
||||
const BIG_PAD_Y = 4;
|
||||
const BIG_PAD_X = 30;
|
||||
// A number row in the big look (Integer and Float): one large centred number
|
||||
// between a step arrow on each side, in a field as wide as the card, with the
|
||||
// gear in its corner as on Text.
|
||||
const BIG_NUMBER_FONT = 30;
|
||||
|
||||
export function ensureCardCss() {
|
||||
if (document.getElementById(CSS_ID)) return;
|
||||
@@ -123,6 +127,19 @@ export function ensureCardCss() {
|
||||
.ausboss-card.look-big .ausboss-card-row.area .ausboss-card-field:focus-within{border-color:${BRAND}}
|
||||
.ausboss-card.look-big .ausboss-card-area{position:absolute;left:0;right:0;top:0;bottom:0;margin:auto 0;max-height:100%;padding:${BIG_PAD_Y}px ${BIG_PAD_X}px;border:none;border-radius:5px;background:transparent;color:#6fe0d6;text-shadow:0 0 .35em rgba(0,180,170,.55);font:600 ${BIG_FONT}px/${BIG_LINE}px ${FONT};text-align:center;scrollbar-width:thin;scrollbar-color:#2f3d3c transparent}
|
||||
.ausboss-card.look-big .ausboss-card-area::placeholder{color:#4f6462;text-shadow:none}
|
||||
.ausboss-card.look-big .ausboss-card-row:not(.area){display:block}
|
||||
.ausboss-card.look-big .ausboss-card-row:not(.area) .ausboss-card-label{display:none}
|
||||
.ausboss-card.look-big .ausboss-card-row:not(.area) .ausboss-card-control{margin:0}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub{height:100%;justify-content:center;align-items:center;gap:4px;border-color:#2a3437;border-radius:6px;background:#0b0f10}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub:focus-within{border-color:${BRAND}}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub>.ausboss-scrub-input{order:1;flex:0 0 auto;width:auto;min-width:2ch;max-width:60%;field-sizing:content;color:#6fe0d6;text-shadow:0 0 .35em rgba(0,180,170,.55);font:600 ${BIG_NUMBER_FONT}px ${FONT}}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub>.ausboss-scrub-unit{order:2}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub>.ausboss-scrub-unit:empty{display:none}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub>.ausboss-scrub-step{display:contents}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub>.ausboss-scrub-step>button{flex:none;width:30px;height:30px;border-radius:15px;color:#6f8886}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub>.ausboss-scrub-step>button:first-child{order:3}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub>.ausboss-scrub-step>button:last-child{order:0}
|
||||
.ausboss-card.look-big .ausboss-card-field>.ausboss-scrub>.ausboss-scrub-step>button>svg{transform:rotate(90deg) scale(1.6)}
|
||||
.ausboss-card.look-big .ausboss-card-corner{top:${CARD_PADDING + 4}px;right:12px;height:22px}
|
||||
.ausboss-card.look-big .ausboss-card-gear{width:22px;height:22px;border-color:transparent;background:transparent}
|
||||
.ausboss-card.look-big .ausboss-card-gear:hover{border-color:${BRAND}}
|
||||
@@ -723,9 +740,10 @@ export function mountWidgetCard(node, { rows, minWidth = 300, first = false, hid
|
||||
if (state.look) root.classList.remove(`look-${state.look}`);
|
||||
if (look) root.classList.add(`look-${look}`);
|
||||
state.look = look;
|
||||
// A textarea row takes its height in this look.
|
||||
// A textarea row, and any row with a height of its own in some look,
|
||||
// takes its height in this look.
|
||||
for (const entry of state.rows) {
|
||||
if (entry.row.kind !== "textarea") continue;
|
||||
if (entry.row.kind !== "textarea" && !entry.row.looks) continue;
|
||||
const height = `${rowHeight(entry.row, look)}px`;
|
||||
if (entry.row.grow) entry.element.style.minHeight = height;
|
||||
else entry.element.style.height = height;
|
||||
|
||||
+22
-12
@@ -16,7 +16,7 @@ import { SOCKETLESS_CHOICE, SOCKETLESS_TEXT, commitWidgetValue, markSocketless,
|
||||
import { mediaViewQuery } from "../shared/media_list.mjs";
|
||||
import { gearIconSvg, openSettingsMenu } from "../shared/settings_menu.mjs";
|
||||
import { SEAM_MENU, SEAM_MUTE_TITLES, isBlendIn, seamCornerReserve } from "../shared/stitch_seam.mjs";
|
||||
import { TEXT_LOOK_MENU, setTextLook, textLook, textLookCornerReserve } from "../shared/text_look.mjs";
|
||||
import { NUMBER_LOOK_MENU, TEXT_LOOK_MENU, setTextLook, textLook, textLookCornerReserve } from "../shared/text_look.mjs";
|
||||
import { fineEdgeLabel } from "../shared/touch_math.mjs";
|
||||
import { valueToTake, wiredLimits } from "../shared/wired_limits.mjs";
|
||||
|
||||
@@ -69,20 +69,21 @@ function seamCorner(node, card) {
|
||||
},
|
||||
};
|
||||
}
|
||||
// Text: the gear in the card's corner picks the node's look, the usual box
|
||||
// or big centred letters (shared/text_look.mjs). The look is kept on the
|
||||
// node, not in a widget, so the node's inputs and saved values never change.
|
||||
function textLookCorner(node, card) {
|
||||
// Text, Integer and Float: the gear in the card's corner picks the node's
|
||||
// look, the usual box or big and centred (shared/text_look.mjs). The look is
|
||||
// kept on the node, not in a widget, so the node's inputs and saved values
|
||||
// never change.
|
||||
const lookCorner = (schema, title) => (node, card) => {
|
||||
const gear = document.createElement("button");
|
||||
gear.type = "button";
|
||||
gear.className = "ausboss-card-gear";
|
||||
gear.title = "Text settings";
|
||||
gear.title = title;
|
||||
gear.innerHTML = gearIconSvg();
|
||||
gear.addEventListener("click", () => openSettingsMenu({
|
||||
scope: "text_look",
|
||||
schema: TEXT_LOOK_MENU,
|
||||
schema,
|
||||
anchor: gear.getBoundingClientRect(),
|
||||
title: "Text settings",
|
||||
title,
|
||||
initial: { look: textLook(node) },
|
||||
onChange: (values) => {
|
||||
if (values.look === textLook(node)) return;
|
||||
@@ -93,7 +94,9 @@ function textLookCorner(node, card) {
|
||||
},
|
||||
}));
|
||||
return { element: gear, sync: () => textLookCornerReserve(textLook(node)) };
|
||||
}
|
||||
};
|
||||
const textLookCorner = lookCorner(TEXT_LOOK_MENU, "Text settings");
|
||||
const numberLookCorner = lookCorner(NUMBER_LOOK_MENU, "Number settings");
|
||||
// Save Video rows that only some formats read (crf, save_metadata).
|
||||
const formatReads = (name) => (values) => formatWidgetVisibility(String(values.format))[name];
|
||||
|
||||
@@ -306,9 +309,16 @@ const CARDS = {
|
||||
// Like ComfyUI's own Primitive node, both take over the limits of the
|
||||
// input they are wired to: wired to a sampler's denoise, Float stops at 1.
|
||||
// A new box also takes the value of the first input it is wired to
|
||||
// (`takesWired`), so wiring it up does not change that setting.
|
||||
AUSBOSS_NODES_Integer: { minWidth: 260, takesWired: "value", rows: [{ widget: "value", label: "Value", limits: wiredLimits }] },
|
||||
AUSBOSS_NODES_Float: { minWidth: 260, takesWired: "value", rows: [{ widget: "value", label: "Value", decimals: 3, trimZeros: true, limits: wiredLimits }] },
|
||||
// (`takesWired`), so wiring it up does not change that setting. The gear
|
||||
// picks the look; big is one large centred number.
|
||||
AUSBOSS_NODES_Integer: {
|
||||
minWidth: 260, takesWired: "value", look: textLook, corner: numberLookCorner,
|
||||
rows: [{ widget: "value", label: "Value", limits: wiredLimits, looks: { big: { height: 56 } } }],
|
||||
},
|
||||
AUSBOSS_NODES_Float: {
|
||||
minWidth: 260, takesWired: "value", look: textLook, corner: numberLookCorner,
|
||||
rows: [{ widget: "value", label: "Value", decimals: 3, trimZeros: true, limits: wiredLimits, looks: { big: { height: 56 } } }],
|
||||
},
|
||||
// The gear picks the look; big is a compact field of large centred
|
||||
// letters, for a word or two over a picture.
|
||||
AUSBOSS_NODES_Text: {
|
||||
|
||||
@@ -179,7 +179,7 @@ test("zeroes the steps never reach are dropped, a value that uses them is shown
|
||||
|
||||
test("Float 🆎 drops the zeroes its steps never reach", () => {
|
||||
const cards = readFileSync(join(ROOT, "js", "widget_cards", "index.js"), "utf-8");
|
||||
assert.match(cards, /AUSBOSS_NODES_Float: \{[^\n]*\btrimZeros: true\b/);
|
||||
assert.match(cards, /AUSBOSS_NODES_Float: \{[\s\S]{0,200}?\btrimZeros: true\b/);
|
||||
});
|
||||
|
||||
test("a sum typed into a number box comes to its answer", () => {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import {
|
||||
TEXT_LOOKS, TEXT_LOOK_MENU, TEXT_LOOK_PROPERTY, setTextLook, textLook, textLookCornerReserve,
|
||||
NUMBER_LOOK_MENU, TEXT_LOOKS, TEXT_LOOK_MENU, TEXT_LOOK_PROPERTY, setTextLook, textLook, textLookCornerReserve,
|
||||
} from "../js/shared/text_look.mjs";
|
||||
import { nodeHeightAfterCardChange } from "../js/shared/panel_layout.mjs";
|
||||
import { CARD_PADDING, cardChangeRestore, cardHeight, rowHeight } from "../js/shared/widget_card_math.mjs";
|
||||
@@ -149,3 +149,55 @@ test("the look adds no input: the Text node still takes its one text box", () =>
|
||||
const api = JSON.parse(read("tests", "fixtures", "node_api.json"));
|
||||
assert.deepEqual(api.AUSBOSS_NODES_Text, { required: ["text"], optional: [], outputs: [["STRING", "text"]] });
|
||||
});
|
||||
|
||||
// Integer and Float take the same two looks from their own gear.
|
||||
function card(name) {
|
||||
const source = read("js", "widget_cards", "index.js");
|
||||
const start = source.indexOf(`\n ${name}: {`);
|
||||
assert.ok(start >= 0, `js/widget_cards/index.js has no card for ${name}`);
|
||||
const next = source.slice(start + 1).search(/\n {2}(\/\/|AUSBOSS_NODES_\w+: \{)/);
|
||||
return source.slice(start, start + 1 + next);
|
||||
}
|
||||
|
||||
test("Integer and Float take the big look from the node, with the number gear in the corner", () => {
|
||||
for (const name of ["AUSBOSS_NODES_Integer", "AUSBOSS_NODES_Float"]) {
|
||||
const entry = card(name);
|
||||
assert.match(entry, /look: textLook/, name);
|
||||
assert.match(entry, /corner: numberLookCorner/, name);
|
||||
assert.match(entry, /looks: \{ big: \{ height: 56 \} \}/, name);
|
||||
// The usual box is unchanged.
|
||||
assert.match(entry, /widget: "value", label: "Value"/, name);
|
||||
}
|
||||
});
|
||||
|
||||
test("the number gear offers the same looks, said for a number", () => {
|
||||
const [look] = NUMBER_LOOK_MENU;
|
||||
assert.equal(NUMBER_LOOK_MENU.length, 1);
|
||||
assert.equal(look.key, "look");
|
||||
assert.deepEqual(look.options, TEXT_LOOKS);
|
||||
assert.equal(look.default, "normal");
|
||||
assert.equal(look.persist, false);
|
||||
assert.match(look.optionHints.big, /number/);
|
||||
// A big number row is taller than a usual one and the card grows with it.
|
||||
const row = { widget: "value", label: "Value", looks: { big: { height: 56 } } };
|
||||
assert.equal(rowHeight(row, "big"), 56);
|
||||
assert.ok(cardHeight([row], "big") > cardHeight([row], "normal"));
|
||||
});
|
||||
|
||||
test("a row with a height of its own in a look takes it when the look changes", () => {
|
||||
const source = read("js", "shared", "widget_card.mjs");
|
||||
assert.match(source, /entry\.row\.kind !== "textarea" && !entry\.row\.looks/);
|
||||
});
|
||||
|
||||
test("a big number sits between its two arrows, in a field as wide as the card", () => {
|
||||
const source = read("js", "shared", "widget_card.mjs");
|
||||
const rule = (tail) => source.match(new RegExp(`\\n\\.ausboss-card\\.look-big \\.ausboss-card-field>\\.ausboss-scrub${tail}\\{([^\\n]*)`))?.[1] ?? "";
|
||||
assert.match(rule(""), /justify-content:center/);
|
||||
assert.match(rule(">\\.ausboss-scrub-step"), /display:contents/);
|
||||
// Down on the left, up on the right, the number between them.
|
||||
assert.match(rule(">\\.ausboss-scrub-step>button:last-child"), /order:0/);
|
||||
assert.match(rule(">\\.ausboss-scrub-input"), /order:1/);
|
||||
assert.match(rule(">\\.ausboss-scrub-step>button:first-child"), /order:3/);
|
||||
// No room held at the sides: the gear sits in the field's corner.
|
||||
assert.match(source, /look-big \.ausboss-card-row:not\(\.area\) \.ausboss-card-control\{margin:0\}/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user