@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
312 lines (311 loc) • 11.9 kB
JavaScript
"use strict";
import { CoreString } from "../../../../core/String";
import { NodeEvent } from "../../../poly/NodeEvent";
import { CoreNodeSelection } from "../../../../core/NodeSelection";
import { Poly } from "../../../Poly";
import { SopOperationContainer } from "../../../operations/container/sop";
import {
addToSetAtEntry,
pushOnArrayAtEntry,
removeFromSetAtEntry,
popFromArrayAtEntry
} from "../../../../core/MapUtils";
import { NameController } from "../NameController";
import { arrayCopy } from "../../../../core/ArrayUtils";
export class HierarchyChildrenController {
constructor(node, _context) {
this.node = node;
this._context = _context;
this._childrenByName = /* @__PURE__ */ new Map();
this._childrenIdByType = /* @__PURE__ */ new Map();
this._childrenByType = /* @__PURE__ */ new Map();
this._childrenAndGrandchildrenByContext = /* @__PURE__ */ new Map();
this._children = [];
this._childrenNames = [];
}
get selection() {
return this._selection = this._selection || new CoreNodeSelection(this.node);
}
dispose() {
const _tmpChildren = [];
arrayCopy(this.children(), _tmpChildren);
for (const child of _tmpChildren) {
this.node.removeNode(child);
}
_tmpChildren.length = 0;
this._selection = void 0;
}
get context() {
return this._context;
}
setOutputNodeFindMethod(method) {
this._outputNodeFindMethod = method;
}
outputNode() {
if (this._outputNodeFindMethod) {
return this._outputNodeFindMethod();
}
}
//
//
//
//
//
setChildName(node, newName) {
let currentChildWithName;
newName = CoreString.sanitizeName(newName);
if ((currentChildWithName = this._childrenByName.get(newName)) != null) {
if (node.name() === newName && currentChildWithName.graphNodeId() === node.graphNodeId()) {
return;
}
newName = CoreString.increment(newName);
return this.setChildName(node, newName);
} else {
const currentName = node.name();
const currentChild = this._childrenByName.get(currentName);
if (currentChild) {
this._childrenByName.delete(currentName);
}
this._childrenByName.set(newName, node);
this._updateCache();
node.nameController.updateNameFromParent(newName);
this.node.scene().nodesController.addToInstanciatedNode(node);
this.node.scene().graphNodesController.notifyNodePathChanged(node);
}
}
_nextAvailableChildName(nodeName) {
nodeName = CoreString.sanitizeName(nodeName);
return this._childrenByName.get(nodeName) ? this._nextAvailableChildName(CoreString.increment(nodeName)) : nodeName;
}
nodeContextSignature() {
return `${this.node.context()}/${this.node.type()}`;
}
availableChildrenClasses() {
return Poly.registeredNodes(this.node);
}
isValidChildType(node_type) {
const node_class = this.availableChildrenClasses()[node_type];
return node_class != null;
}
// create_node(node_type: string, options?: NodeCreateOptions): BaseNodeType {
// const node_class = this.available_children_classes()[node_type];
// if (node_class == null) {
// const message = `child node type '${node_type}' not found for node '${this.node.path()}'. Available types are: ${Object.keys(
// this.available_children_classes()
// ).join(', ')}, ${this._context}, ${this.node.type}`;
// console.error(message);
// throw message;
// } else {
// const child_node = new node_class(this.node.scene, `child_node_${node_type}`, paramsInitValueOverrides);
// child_node.initialize_base_and_node();
// this.add_node(child_node);
// child_node.lifecycle.set_creation_completed();
// return child_node;
// }
// }
createNode(nodeClassOrString, options) {
if (typeof nodeClassOrString == "string") {
const nodeClass = this._findNodeClass(nodeClassOrString);
return this._createAndInitNode(nodeClass, options);
} else {
return this._createAndInitNode(nodeClassOrString, options);
}
}
_createAndInitNode(nodeClass, options) {
var _a;
const requestedNodeName = (options == null ? void 0 : options.nodeName) || NameController.baseName(nodeClass);
const nodeName = this._nextAvailableChildName(requestedNodeName);
const childNode = new nodeClass(this.node.scene(), nodeName, {
...options,
serializerClass: (_a = this.node.serializer) == null ? void 0 : _a.constructor
});
childNode.initializeBaseAndNode();
this._addNode(childNode);
childNode.lifecycle.setCreationCompleted();
return childNode;
}
_findNodeClass(node_type) {
const nodeClass = this.availableChildrenClasses()[node_type.toLowerCase()];
if (nodeClass == null) {
const message = `child node type '${node_type}' not found for node '${this.node.path()}'. Available types are: ${Object.keys(
this.availableChildrenClasses()
).join(", ")}, ${this._context}, ${this.node.type()}`;
console.error(message);
throw message;
}
return nodeClass;
}
createOperationContainer(operationType, operationContainerName, options) {
const operationClass = Poly.registeredOperation(this._context, operationType);
if (operationClass == null) {
const message = `no operation found with context ${this._context}/${operationType}`;
console.error(message);
throw message;
} else {
const operation = new operationClass(this.node.scene());
const operation_container = new SopOperationContainer(
operation,
operationContainerName,
(options == null ? void 0 : options.paramsInitValueOverrides) || {}
);
return operation_container;
}
}
_addNode(childNode) {
childNode.setParent(this.node);
this._addToNodesByType(childNode);
childNode.params.init();
childNode.parentController.onSetParent();
childNode.nameController.runPostSetFullPathHooks();
if (childNode.childrenAllowed() && childNode.childrenController) {
for (const child of childNode.childrenController.children()) {
child.nameController.runPostSetFullPathHooks();
}
}
if (this.node.serializer) {
const childNodeJSON = childNode.toJSON();
if (childNodeJSON) {
this.node.emit(NodeEvent.CREATED, { child_node_json: childNodeJSON });
}
}
if (this.node.scene().lifecycleController.onAfterCreatedCallbackAllowed()) {
childNode.lifecycle.runOnAfterCreatedCallbacks();
}
childNode.lifecycle.runOnAfterAddedCallbacks();
this.node.lifecycle.runOnChildAddCallbacks(childNode);
if (childNode.requireWebGL2()) {
this.node.scene().webglController.setRequireWebGL2();
}
this.node.scene().missingExpressionReferencesController.checkForMissingNodeReferences(childNode);
return childNode;
}
removeNode(childNode) {
var _a;
if (this.node.lockedOrInsideALockedParent()) {
const lockedNode = this.node.selfOrLockedParent();
const reason = lockedNode == this.node ? `it is locked` : `it is inside '${lockedNode ? lockedNode.path() : ""}', which is locked`;
console.warn(`node '${this.node.path()}' cannot remove nodes, since ${reason}`);
console.log(this.node.graphNodeId(), this.node.name());
return;
}
if (childNode.parent() != this.node) {
return console.warn(`node ${childNode.name()} not under parent ${this.node.path()}`);
} else {
(_a = childNode.polyNodeController) == null ? void 0 : _a.setLockedState(false);
childNode.lifecycle.runOnBeforeDeleteCallbacks();
if (this.selection.contains(childNode)) {
this.selection.remove([childNode]);
}
const firstConnection = childNode.io.connections.firstInputConnection();
const inputConnections = childNode.io.connections.inputConnections();
const outputConnections = [];
childNode.io.connections.outputConnections(outputConnections);
if (inputConnections) {
for (const inputConnection of inputConnections) {
if (inputConnection) {
inputConnection.disconnect({ setInput: true });
}
}
}
if (outputConnections) {
for (const outputConnection of outputConnections) {
if (outputConnection) {
outputConnection.disconnect({ setInput: true });
if (firstConnection) {
const oldSrc = firstConnection.nodeSrc();
const oldOutputIndex = firstConnection.outputIndex();
const oldDest = outputConnection.nodeDest();
const oldInputIndex = outputConnection.inputIndex();
oldDest.io.inputs.setInput(oldInputIndex, oldSrc, oldOutputIndex);
}
}
}
}
childNode.setParent(null);
this._childrenByName.delete(childNode.name());
this._updateCache();
this._removeFromNodesByType(childNode);
this.node.scene().nodesController.removeFromInstanciatedNode(childNode);
childNode.setSuccessorsDirty(this.node);
childNode.graphDisconnectSuccessors();
this.node.lifecycle.runOnChildRemoveCallbacks(childNode);
childNode.lifecycle.runOnDeleteCallbacks();
childNode.dispose();
childNode.emit(NodeEvent.DELETED, { parent_id: this.node.graphNodeId() });
this.node.scene().graphNodesController.notifyNodePathChanged(childNode);
}
}
_addToNodesByType(node) {
const nodeId = node.graphNodeId();
const type = node.type();
addToSetAtEntry(this._childrenIdByType, type, nodeId);
pushOnArrayAtEntry(this._childrenByType, type, node);
this._addToChildrenAndGrandchildrenByContext(node);
}
_removeFromNodesByType(node) {
const nodeId = node.graphNodeId();
const type = node.type();
removeFromSetAtEntry(this._childrenIdByType, type, nodeId);
popFromArrayAtEntry(this._childrenByType, type, node);
this._removeFromChildrenAndGrandchildrenByContext(node);
}
_addToChildrenAndGrandchildrenByContext(node) {
var _a;
const nodeId = node.graphNodeId();
const nodeContext = node.context();
addToSetAtEntry(this._childrenAndGrandchildrenByContext, nodeContext, nodeId);
const parent = this.node.parent();
if (parent && parent.childrenAllowed()) {
(_a = parent.childrenController) == null ? void 0 : _a._addToChildrenAndGrandchildrenByContext(node);
}
}
_removeFromChildrenAndGrandchildrenByContext(node) {
var _a;
const nodeId = node.graphNodeId();
const type = node.context();
removeFromSetAtEntry(this._childrenAndGrandchildrenByContext, type, nodeId);
const parent = this.node.parent();
if (parent && parent.childrenAllowed()) {
(_a = parent.childrenController) == null ? void 0 : _a._removeFromChildrenAndGrandchildrenByContext(node);
}
}
nodesByType(type, target = []) {
const nodes = this._childrenByType.get(type);
target.length = nodes ? nodes.length : 0;
if (nodes) {
for (let i = 0; i < nodes.length; i++) {
target[i] = nodes[i];
}
}
return target;
}
childByName(name) {
return this._childrenByName.get(name) || null;
}
hasChildrenAndGrandchildrenWithContext(context) {
return this._childrenAndGrandchildrenByContext.get(context) != null;
}
_updateCache() {
this._children.length = 0;
this._childrenNames.length = 0;
this._childrenByName.forEach((node) => {
this._children.push(node);
this._childrenNames.push(node.name());
});
}
children() {
return this._children;
}
childrenNames() {
return this._childrenNames;
}
traverseChildren(callback, conditionCallback) {
this._childrenByName.forEach((childNode) => {
var _a;
callback(childNode);
if (conditionCallback == null || conditionCallback(childNode) == true) {
(_a = childNode.childrenController) == null ? void 0 : _a.traverseChildren(callback);
}
});
}
}