Prechádzať zdrojové kódy

fix connectionPoint.isConnected. fix node port ux bugs

Kyle Belfort 5 rokov pred
rodič
commit
c9ca0e68ef

+ 5 - 0
nodeEditor/src/components/propertyTab/propertyTab.scss

@@ -497,6 +497,11 @@
                 cursor: pointer;
             }
 
+            .cbx ~ label.disabled {
+                background: rgb(85, 85, 85);
+                cursor: pointer;
+            }
+
             .hidden { 
                 display: none; 
             }               

+ 125 - 78
nodeEditor/src/diagram/graphFrame.ts

@@ -53,6 +53,8 @@ export class GraphFrame {
     private _mouseStartPointY: Nullable<number> = null;
     private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphFrame | GraphNode | NodeLink | NodePort | FramePortData>>>;
     private _onGraphNodeRemovalObserver: Nullable<Observer<GraphNode>>; 
+    private _onExposePortOnFrameObserver: Nullable<Observer<GraphNode>>;
+    private _onNodeLinkDisposedObservers: Nullable<Observer<NodeLink>>[] = [];
     private _isCollapsed = false;
     private _frameInPorts: FrameNodePort[] = [];
     private _frameOutPorts: FrameNodePort[] = [];
@@ -87,100 +89,133 @@ export class GraphFrame {
         this._controlledPorts.push(port);
     }
 
-    public set isCollapsed(value: boolean) {
-        if (this._isCollapsed === value) {
-            return;
+    // Mark ports with FramePortPosition for re-arrangement support
+    private _markFramePortPositions() {
+        // mark FrameInPorts 
+         if(this._frameInPorts.length == 2){
+            this._frameInPorts[0].framePortPosition = FramePortPosition.Top;
+            this._frameInPorts[1].framePortPosition = FramePortPosition.Bottom;
+        } else {
+            for(let i = 0; i < this._frameInPorts.length; i++) {
+                const port = this._frameInPorts[i];
+                if(i === 0){
+                    port.framePortPosition = FramePortPosition.Top;
+                } else if(i === this._frameInPorts.length -1){
+                    port.framePortPosition = FramePortPosition.Bottom;
+                } else {
+                    port.framePortPosition = FramePortPosition.Middle;
+                }
+            }
         }
 
-        this._isCollapsed = value;
-        this._ownerCanvas._frameIsMoving = true;
-
-        // Need to delegate the outside ports to the frame
-        if (value) {
-            this.element.classList.add("collapsed");
+        // mark FrameOutPorts
+        if(this._frameOutPorts.length == 2){
+            this._frameOutPorts[0].framePortPosition = FramePortPosition.Top;
+            this._frameOutPorts[1].framePortPosition = FramePortPosition.Bottom;
+        } else {
+            for(let i = 0; i < this._frameOutPorts.length; i++) {
+                const port = this._frameOutPorts[i];
+                if(i === 0){
+                    port.framePortPosition = FramePortPosition.Top
+                } else if(i === this._frameInPorts.length -1){
+                    port.framePortPosition = FramePortPosition.Bottom
+                } else {
+                    port.framePortPosition = FramePortPosition.Middle
+                }
+            }
+        }
+    }
 
-            this._moveFrame((this.width - this.CollapsedWidth) / 2, 0);
+    private _createFramePorts() {
+        for (var node of this._nodes) {
+            node.isVisible = false;
+            for (var port of node.outputPorts) { // Output
+                if (port.connectionPoint.hasEndpoints) {
+                    let portAdded = false;
 
-            for (var node of this._nodes) {
-                node.isVisible = false;
-                for (var port of node.outputPorts) { // Output
-                    if (port.connectionPoint.hasEndpoints) {
-                        let portAdded = false;
+                    for (var link of node.links) {
+                        if (link.portA === port && this.nodes.indexOf(link.nodeB!) === -1) {
+                            let localPort: FrameNodePort;
 
-                        for (var link of node.links) {
-                            if (link.portA === port && this.nodes.indexOf(link.nodeB!) === -1) {
-                                let localPort: FrameNodePort;
+                            if (!portAdded) {
+                                portAdded = true;
+                                localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++, this.id);
+                                this._frameOutPorts.push(localPort);
 
-                                if (!portAdded) {
-                                    portAdded = true;
-                                    localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++, this.id);
-                                    this._frameOutPorts.push(localPort);
+                                link.isVisible = true;
 
-                                    link.isVisible = true;
+                                const onLinkDisposedObserver = link.onDisposedObservable.add((nodeLink: NodeLink) => {
+                                    this._redrawFramePorts();
+                                });
 
-                                } else {
-                                    localPort = this.ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
-                                }
+                                this._onNodeLinkDisposedObservers.push(onLinkDisposedObserver); 
 
-                                port.delegatedPort = localPort;
-                                this._controlledPorts.push(port);
+                            } else {
+                                localPort = this.ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
                             }
-                        }
-                    } else if(port.exposedOnFrame) {
-                        let localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++, this.id);
-                        this._frameOutPorts.push(localPort);
-                        port.delegatedPort = localPort;
-                        this._controlledPorts.push(port);
-                    }
-                }
 
-                for (var port of node.inputPorts) { // Input
-                    if (port.connectionPoint.isConnected) {
-                        for (var link of node.links) {
-                            if (link.portB === port && this.nodes.indexOf(link.nodeA) === -1) {
-                                this._createInputPort(port, node);
-                                link.isVisible = true;
-                            }
+                            port.delegatedPort = localPort;
+                            this._controlledPorts.push(port);
                         }
-                    } else if(port.exposedOnFrame) {
-                        this._createInputPort(port, node);
                     }
+                } else if(port.exposedOnFrame) {
+                    let localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++, this.id);
+                    this._frameOutPorts.push(localPort);
+                    port.delegatedPort = localPort;
+                    this._controlledPorts.push(port);
                 }
             }
 
-            // mark FrameInPorts with position
-            if(this._frameInPorts.length == 2){
-                this._frameInPorts[0].framePortPosition = FramePortPosition.Top;
-                this._frameInPorts[1].framePortPosition = FramePortPosition.Bottom;
-            } else {
-                for(let i = 0; i < this._frameInPorts.length; i++) {
-                    const port = this._frameInPorts[i];
-                    if(i === 0){
-                        port.framePortPosition = FramePortPosition.Top;
-                    } else if(i === this._frameInPorts.length -1){
-                        port.framePortPosition = FramePortPosition.Bottom;
-                    } else {
-                        port.framePortPosition = FramePortPosition.Middle;
+            for (var port of node.inputPorts) { // Input
+                if (port.connectionPoint.isConnected) {
+                    for (var link of node.links) {
+                        if (link.portB === port && this.nodes.indexOf(link.nodeA) === -1) {
+                            this._createInputPort(port, node);
+                            link.isVisible = true;
+                            
+                            const onLinkDisposedObserver = link.onDisposedObservable.add((nodeLink: NodeLink) => {
+                                this._redrawFramePorts();
+                            });
+
+                            this._onNodeLinkDisposedObservers.push(onLinkDisposedObserver);
+                        }
                     }
+                } else if(port.exposedOnFrame) {
+                    this._createInputPort(port, node);
                 }
             }
+        }
+    }
+    
+    private _redrawFramePorts() {
+        if(!this.isCollapsed) {
+            return;
+        }
+        this.ports.forEach((framePort:FrameNodePort) => {
+            framePort.dispose()
+        });
 
-            // mark FrameOutPorts with position
-            if(this._frameOutPorts.length == 2){
-                this._frameOutPorts[0].framePortPosition = FramePortPosition.Top;
-                this._frameOutPorts[1].framePortPosition = FramePortPosition.Bottom;
-            } else {
-                for(let i = 0; i < this._frameOutPorts.length; i++) {
-                    const port = this._frameOutPorts[i];
-                    if(i === 0){
-                        port.framePortPosition = FramePortPosition.Top
-                    } else if(i === this._frameInPorts.length -1){
-                        port.framePortPosition = FramePortPosition.Bottom
-                    } else {
-                        port.framePortPosition = FramePortPosition.Middle
-                    }
-                }
-            }
+        this._createFramePorts();
+        this.ports.forEach((framePort: FrameNodePort) => framePort.node._refreshLinks());
+    }
+
+    public set isCollapsed(value: boolean) {
+        if (this._isCollapsed === value) {
+            return;
+        }
+
+        this._isCollapsed = value;
+        this._ownerCanvas._frameIsMoving = true;
+
+        // Need to delegate the outside ports to the frame
+        if (value) {
+            this.element.classList.add("collapsed");
+
+            this._moveFrame((this.width - this.CollapsedWidth) / 2, 0);
+
+            this._createFramePorts()
+
+            this._markFramePortPositions()
 
         } else {
             this.element.classList.remove("collapsed");
@@ -203,6 +238,7 @@ export class GraphFrame {
             this._frameInPorts = [];
             this._frameOutPorts = [];
             this._controlledPorts = [];
+            this._onNodeLinkDisposedObservers = [];
 
             for (var node of this._nodes) {
                 node.isVisible = true;
@@ -224,7 +260,7 @@ export class GraphFrame {
         }
 
         this.onExpandStateChanged.notifyObservers(this);
-    }
+    }     
 
     public get nodes() {
         return this._nodes;
@@ -486,6 +522,13 @@ export class GraphFrame {
             }
         });
 
+        this._onExposePortOnFrameObserver = canvas.globalState.onExposePortOnFrameObservable.add((node: GraphNode) => {
+            if (this.nodes.indexOf(node) === -1) {
+                return;
+            }
+            this._redrawFramePorts();
+        });
+
         this._commentsElement = document.createElement('div');
         this._commentsElement.className = 'frame-comments';
         this._commentsElement.style.color = 'white';
@@ -1208,11 +1251,15 @@ export class GraphFrame {
 
         if (this._onSelectionChangedObserver) {
             this._ownerCanvas.globalState.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
-        }
+        };
 
         if(this._onGraphNodeRemovalObserver) {
             this._ownerCanvas.globalState.onGraphNodeRemovalObservable.remove(this._onGraphNodeRemovalObserver);
-        }
+        };
+
+        if(this._onExposePortOnFrameObserver) {
+            this._ownerCanvas.globalState.onExposePortOnFrameObservable.remove(this._onExposePortOnFrameObserver);
+        };
 
         this.element.parentElement!.removeChild(this.element);
 
@@ -1260,7 +1307,7 @@ export class GraphFrame {
 
                 if (node.length) {
                     newFrame.nodes.push(node[0]);
-                    node[0].isEnclosedInAFrame = true;
+                    node[0].enclosingFrameId = newFrame.id;
                 }
             }
         } else {

+ 8 - 6
nodeEditor/src/diagram/graphNode.ts

@@ -39,7 +39,7 @@ export class GraphNode {
     private _isSelected: boolean;
     private _displayManager: Nullable<IDisplayManager> = null;
     private _isVisible = true;
-    private _isEnclosedInAFrame: boolean;
+    private _enclosingFrameId: number;
 
     public get isVisible() {
         return this._isVisible;
@@ -145,12 +145,12 @@ export class GraphNode {
         return this._isSelected;
     }
 
-    public get isEnclosedInAFrame() {
-        return this._isEnclosedInAFrame;
+    public get enclosingFrameId() {
+        return this._enclosingFrameId;
     }
 
-    public set isEnclosedInAFrame(value: boolean) {
-        this._isEnclosedInAFrame = value;
+    public set enclosingFrameId(value: number) {
+        this._enclosingFrameId = value;
     }
 
     public set isSelected(value: boolean) {
@@ -225,7 +225,9 @@ export class GraphNode {
             rect1.bottom < rect2.top || 
             rect1.top > rect2.bottom);
 
-        this._isEnclosedInAFrame = isOverlappingFrame;
+        if (isOverlappingFrame) {
+            this.enclosingFrameId = frame.id;
+        }
         return isOverlappingFrame;
     }
 

+ 2 - 0
nodeEditor/src/diagram/nodeLink.ts

@@ -148,5 +148,7 @@ export class NodeLink {
         }
 
         this.onDisposedObservable.notifyObservers(this);
+
+        this.onDisposedObservable.clear();
     }
 }

+ 15 - 3
nodeEditor/src/diagram/nodePort.ts

@@ -19,7 +19,7 @@ export class NodePort {
     protected _portLabelElement: Element;
     protected _onCandidateLinkMovedObserver: Nullable<Observer<Nullable<Vector2>>>;
     protected _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphFrame | GraphNode | NodeLink | NodePort | FramePortData>>>;
-    protected _exposedOnFrame = this.connectionPoint.isConnectedToAnything || false;
+    protected _exposedOnFrame: boolean;
     
     public delegatedPort: Nullable<FrameNodePort> = null;
 
@@ -51,7 +51,17 @@ export class NodePort {
     }
 
     public get exposedOnFrame() {
-        return this.connectionPoint.isConnectedToAnything || this._exposedOnFrame;
+        return (this.connectionPoint.isConnected || !!this._exposedOnFrame) && !this._isConnectedToNodeInsideSameFrame() ;
+    }
+
+    private _isConnectedToNodeInsideSameFrame(){
+        const link = this.node.getLinksForConnectionPoint(this.connectionPoint)
+        if (link.length){
+            if (link[0].nodeA.enclosingFrameId == link[0].nodeB!.enclosingFrameId) {
+                return true;
+            }
+        }
+        return false;
     }
 
     public set exposedOnFrame(value: boolean) {
@@ -85,7 +95,7 @@ export class NodePort {
         }
     }
 
-    public constructor(portContainer: HTMLElement, public connectionPoint: NodeMaterialConnectionPoint, public node: GraphNode, globalState: GlobalState) {
+    public constructor(private portContainer: HTMLElement, public connectionPoint: NodeMaterialConnectionPoint, public node: GraphNode, globalState: GlobalState) {
         this._element = portContainer.ownerDocument!.createElement("div");
         this._element.classList.add("port");
         portContainer.appendChild(this._element);
@@ -133,6 +143,8 @@ export class NodePort {
         if (this._onSelectionChangedObserver) {
             this._globalState.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
         }
+
+        this.portContainer.remove();
     }
 
     public static CreatePortElement(connectionPoint: NodeMaterialConnectionPoint, node: GraphNode, root: HTMLElement, 

+ 6 - 1
nodeEditor/src/diagram/properties/nodePortPropertyComponent.tsx

@@ -28,6 +28,11 @@ export class NodePortPropertyTabComponent extends React.Component<IFrameNodePort
         this.props.globalState.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
     }
 
+    toggleExposeOnFrame(value: boolean){
+        this.props.nodePort.exposedOnFrame = value;
+        this.props.globalState.onExposePortOnFrameObservable.notifyObservers(this.props.nodePort.node);
+    }
+
     render() {
         return (
             <div id="propertyTab">
@@ -40,7 +45,7 @@ export class NodePortPropertyTabComponent extends React.Component<IFrameNodePort
                 <div>
                     <LineContainerComponent title="GENERAL">
                         {this.props.nodePort.hasLabel() && <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portName" target={this.props.nodePort} />}
-                        {this.props.nodePort.node.isEnclosedInAFrame && <CheckBoxLineComponent label= "Expose Port on Frame" target={this.props.nodePort} isSelected={() => this.props.nodePort.exposedOnFrame} onSelect={(value: boolean) => this.props.nodePort.exposedOnFrame = value}  propertyName="exposedOnFrame" disabled={this.props.nodePort.connectionPoint.isConnectedToAnything} />}
+                        {this.props.nodePort.node.enclosingFrameId !== undefined && <CheckBoxLineComponent label= "Expose Port on Frame" target={this.props.nodePort} isSelected={() => this.props.nodePort.exposedOnFrame} onSelect={(value: boolean) => this.toggleExposeOnFrame(value)}  propertyName="exposedOnFrame" disabled={this.props.nodePort.connectionPoint.isConnected} />}
                     </LineContainerComponent>
                 </div>
             </div>

+ 1 - 0
nodeEditor/src/globalState.ts

@@ -42,6 +42,7 @@ export class GlobalState {
     onGraphNodeRemovalObservable = new Observable<GraphNode>();
     onGetNodeFromBlock: (block: NodeMaterialBlock) => GraphNode;
     onGridSizeChanged = new Observable<void>();
+    onExposePortOnFrameObservable = new Observable<GraphNode>();
     previewMeshType: PreviewMeshType;
     previewMeshFile: File;
     listOfCustomPreviewMeshFiles: File[] = [];

+ 1 - 9
src/Materials/Node/nodeMaterialBlockConnectionPoint.ts

@@ -181,15 +181,7 @@ export class NodeMaterialConnectionPoint {
      * Gets a boolean indicating that the current point is connected to another NodeMaterialBlock
      */
     public get isConnected(): boolean {
-        return this.connectedPoint !== null;
-    }
-
-    /**
-     * Gets a boolean indicating that the current point is connected to anything (another NodeMaterialBlock, a shader, or a Input Block, etc).
-     */
-    public get isConnectedToAnything() {
-        return this.connectedPoint !== null || this.isConnectedInFragmentShader || this.isConnectedInVertexShader || this.isConnectedToInputBlock || this._endpoints.length > 0;
-
+        return this.connectedPoint !== null || this.hasEndpoints;
     }
 
     /**