Browse Source

Merge pull request #8026 from belfortk/frame-ports-optional

Make Frame ports optional
David Catuhe 5 years ago
parent
commit
1beadf4801

File diff suppressed because it is too large
+ 1241 - 1237
dist/preview release/babylon.module.d.ts


+ 1 - 0
dist/preview release/what's new.md

@@ -27,6 +27,7 @@
 - Frames are now resizable from the corners ([belfortk](https://github.com/belfortk)
 - Can now rename and re-order frame inputs and outputs ([belfortk](https://github.com/belfortk)
 - Can now edit Node port names ([belfortk](https://github.com/belfortk)
+- Updated which node ports are shown on frames by default so that only node ports connected to outside nodes are by default exposed on the frame ([belfortk](https://github.com/belfortk)
 
 ### Inspector
 

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

@@ -486,6 +486,22 @@
                 background: rgb(22, 73, 117);
             }
 
+            .cbx:checked ~ label.disabled { 
+                background: rgb(22, 73, 117);
+                cursor: pointer;
+            }
+
+            .cbx:checked ~ label.disabled:after {
+                left: 20px;
+                background: rgb(85, 85, 85);
+                cursor: pointer;
+            }
+
+            .cbx ~ label.disabled {
+                background: rgb(85, 85, 85);
+                cursor: pointer;
+            }
+
             .hidden { 
                 display: none; 
             }               

+ 5 - 1
nodeEditor/src/diagram/frameNodePort.ts

@@ -72,7 +72,11 @@ export class FrameNodePort extends NodePort {
         if (!displayManager || displayManager.shouldDisplayPortLabels(block)) {
             let portLabel = root.ownerDocument!.createElement("div");
             portLabel.classList.add("port-label");
-            portLabel.innerHTML = connectionPoint.displayName || connectionPoint.name;        
+            let portName = connectionPoint.displayName || connectionPoint.name;
+            if (connectionPoint.ownerBlock.isInput) {
+                portName = node.name;
+            }
+            portLabel.innerHTML = portName;       
             portContainer.appendChild(portLabel);
         }
 

+ 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,101 +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 {
-                        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 {
-                        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");
@@ -204,6 +238,7 @@ export class GraphFrame {
             this._frameInPorts = [];
             this._frameOutPorts = [];
             this._controlledPorts = [];
+            this._onNodeLinkDisposedObservers = [];
 
             for (var node of this._nodes) {
                 node.isVisible = true;
@@ -225,7 +260,7 @@ export class GraphFrame {
         }
 
         this.onExpandStateChanged.notifyObservers(this);
-    }
+    }     
 
     public get nodes() {
         return this._nodes;
@@ -487,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';
@@ -1209,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);
 
@@ -1261,6 +1307,7 @@ export class GraphFrame {
 
                 if (node.length) {
                     newFrame.nodes.push(node[0]);
+                    node[0].enclosingFrameId = newFrame.id;
                 }
             }
         } else {

+ 15 - 1
nodeEditor/src/diagram/graphNode.ts

@@ -39,6 +39,7 @@ export class GraphNode {
     private _isSelected: boolean;
     private _displayManager: Nullable<IDisplayManager> = null;
     private _isVisible = true;
+    private _enclosingFrameId: number;
 
     public get isVisible() {
         return this._isVisible;
@@ -144,6 +145,14 @@ export class GraphNode {
         return this._isSelected;
     }
 
+    public get enclosingFrameId() {
+        return this._enclosingFrameId;
+    }
+
+    public set enclosingFrameId(value: number) {
+        this._enclosingFrameId = value;
+    }
+
     public set isSelected(value: boolean) {
         if (this._isSelected === value) {
             return;            
@@ -211,10 +220,15 @@ export class GraphNode {
         rect1.width -= 5;
         rect1.height -= 5;
 
-        return !(rect1.right < rect2.left || 
+        const isOverlappingFrame = !(rect1.right < rect2.left || 
             rect1.left > rect2.right || 
             rect1.bottom < rect2.top || 
             rect1.top > rect2.bottom);
+
+        if (isOverlappingFrame) {
+            this.enclosingFrameId = frame.id;
+        }
+        return isOverlappingFrame;
     }
 
     public getPortForConnectionPoint(point: NodeMaterialConnectionPoint) {

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

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

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

@@ -18,7 +18,8 @@ export class NodePort {
     protected _globalState: GlobalState;
     protected _portLabelElement: Element;
     protected _onCandidateLinkMovedObserver: Nullable<Observer<Nullable<Vector2>>>;
-    protected _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphFrame | GraphNode | NodeLink | NodePort | FramePortData>>>;  
+    protected _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphFrame | GraphNode | NodeLink | NodePort | FramePortData>>>;
+    protected _exposedOnFrame: boolean;
     
     public delegatedPort: Nullable<FrameNodePort> = null;
 
@@ -31,7 +32,11 @@ export class NodePort {
     }
 
     public get portName(){
-        return this.connectionPoint.displayName || this.connectionPoint.name;
+        let portName = this.connectionPoint.displayName || this.connectionPoint.name;
+        if (this.connectionPoint.ownerBlock.isInput) {
+            portName = this.node.name;
+        }
+        return portName
     }
 
     public set portName(newName: string){
@@ -45,6 +50,24 @@ export class NodePort {
         return !!this._portLabelElement;
     }
 
+    public get 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) {
+        this._exposedOnFrame = value;
+    }
+
     public refresh() {
         this._element.style.background = BlockTools.GetColorFromConnectionNodeType(this.connectionPoint.type);
         switch (this.connectionPoint.type) {
@@ -72,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);
@@ -120,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, 

+ 7 - 0
nodeEditor/src/diagram/properties/nodePortPropertyComponent.tsx

@@ -10,6 +10,7 @@ import { NodePort } from '../nodePort';
 import { GraphNode } from '../graphNode';
 import { NodeLink } from '../nodeLink';
 import { FramePortData } from '../graphCanvas';
+import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
 
 export interface IFrameNodePortPropertyTabComponentProps {
     globalState: GlobalState
@@ -27,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">
@@ -39,6 +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.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[] = [];

+ 4 - 3
nodeEditor/src/sharedComponents/checkBoxLineComponent.tsx

@@ -10,6 +10,7 @@ export interface ICheckBoxLineComponentProps {
     onSelect?: (value: boolean) => void;
     onValueChanged?: () => void;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    disabled?: boolean;
 }
 
 export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, { isSelected: boolean }> {
@@ -42,7 +43,7 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
             this._localChange = false;
             return true;
         }
-        return nextProps.label !== this.props.label;
+        return nextProps.label !== this.props.label || nextProps.target !== this.props.target;
     }
 
     onChange() {
@@ -76,8 +77,8 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
                     {this.props.label}
                 </div>
                 <div className="checkBox">
-                    <input type="checkbox" id={"checkbox" + this._uniqueId} className="cbx hidden" checked={this.state.isSelected} onChange={() => this.onChange()} />
-                    <label htmlFor={"checkbox" + this._uniqueId} className="lbl"></label>
+                    <input type="checkbox" id={"checkbox" + this._uniqueId} className="cbx hidden" checked={this.state.isSelected} onChange={() => this.onChange()} disabled={!!this.props.disabled}/>
+                    <label htmlFor={"checkbox" + this._uniqueId} className={`lbl${!!this.props.disabled ? ' disabled' : ''}`}></label>
                 </div>
             </div>
         );

+ 2 - 2
src/Materials/Node/nodeMaterialBlockConnectionPoint.ts

@@ -178,10 +178,10 @@ export class NodeMaterialConnectionPoint {
     }
 
     /**
-     * Gets a boolean indicating that the current point is connected
+     * Gets a boolean indicating that the current point is connected to another NodeMaterialBlock
      */
     public get isConnected(): boolean {
-        return this.connectedPoint !== null;
+        return this.connectedPoint !== null || this.hasEndpoints;
     }
 
     /**