Build a Pack or Expand node's ports from a struct variable
The port editor gets 'From variable' next to '+ Field': pick a struct variable of the behavior and its fields land as ports. It only adds - a field the node already declares stays as it is, because it may carry an edge - and the entry is disabled once there is nothing left to add. A list of structs counts too: it declares the shape of every item, which is exactly the bundle a Pack builds for it. A color field arrives as a number port; the graph has no color type. AddPortsCommand is new underneath: adding five ports had to be one undo step, and it checks every key before it appends a single one, so a collision does not leave half the list behind. AddPortCommand is a three-line subclass of it, which leaves its sixteen call sites untouched.
This commit is contained in:
1 parent
2218046738
commit
14f542365e
10 files changed
+346
-22
No files matched your search
@@ -0,0 +1,34 @@
|
||||
import type { PropertyDef, StructFieldDef } from '../properties/PropertySchema';
|
||||
import { DECLARED_PORT_KINDS, type DeclaredPort, type DeclaredPortKind, type GraphNode } from './Graph';
|
||||
|
||||
/** Every variable kind is a port kind too; the fallback is for a project file that says otherwise. */
|
||||
export function variablePortKind(def: PropertyDef): DeclaredPortKind {
|
||||
return (DECLARED_PORT_KINDS as readonly string[]).includes(def.kind)
|
||||
? (def.kind as DeclaredPortKind)
|
||||
: 'text';
|
||||
}
|
||||
|
||||
/** A color is a number in the value model, and the graph has no port kind of its own for it. */
|
||||
export function fieldPortKind(field: StructFieldDef): DeclaredPortKind {
|
||||
return field.kind === 'color' ? 'number' : field.kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bundle shape a variable declares, if it declares one: a struct variable holds it directly, a
|
||||
* list of structs declares the shape of every item. Both are what a Pack builds and an Expand takes
|
||||
* apart, so both can seed a node's fields.
|
||||
*/
|
||||
export function structShapeOf(def: PropertyDef): readonly StructFieldDef[] | undefined {
|
||||
if (def.kind === 'struct') return def.fields;
|
||||
if (def.kind === 'list' && def.items === 'struct') return def.fields ?? [];
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ports `fields` would add to `node`. A key the node already declares is left alone rather than
|
||||
* retyped: it may carry an edge, and the manual declaration is the one the user typed.
|
||||
*/
|
||||
export function missingFieldPorts(node: GraphNode, fields: readonly StructFieldDef[]): DeclaredPort[] {
|
||||
const taken = new Set((node.ports ?? []).map((p) => p.key));
|
||||
return fields.filter((f) => !taken.has(f.key)).map((f) => ({ key: f.key, kind: fieldPortKind(f) }));
|
||||
}
|
||||
Reference in new issue
Block a user