瀏覽代碼

working on moving node ports

Kyle Belfort 5 年之前
父節點
當前提交
2e383fe561

+ 15 - 5
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -16,6 +16,7 @@ import { GraphFrame } from '../../diagram/graphFrame';
 import { TextLineComponent } from '../../sharedComponents/textLineComponent';
 import { Engine } from 'babylonjs/Engines/engine';
 import { FramePropertyTabComponent } from '../../diagram/properties/framePropertyComponent';
+import { NodePortPropertyTabComponent } from '../../diagram/properties/nodePortPropertyComponent';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes';
 import { Color3LineComponent } from '../../sharedComponents/color3LineComponent';
@@ -25,29 +26,32 @@ import { Vector2LineComponent } from '../../sharedComponents/vector2LineComponen
 import { Vector3LineComponent } from '../../sharedComponents/vector3LineComponent';
 import { Vector4LineComponent } from '../../sharedComponents/vector4LineComponent';
 import { Observer } from 'babylonjs/Misc/observable';
+import { NodePort } from '../../diagram/nodePort';
 require("./propertyTab.scss");
 
 interface IPropertyTabComponentProps {
     globalState: GlobalState;
 }
 
-export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<GraphNode>, currentFrame: Nullable<GraphFrame> }> {
+export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<GraphNode>, currentFrame: Nullable<GraphFrame>, currentNodePort: Nullable<NodePort> }> {
     private _onBuiltObserver: Nullable<Observer<void>>;
 
     constructor(props: IPropertyTabComponentProps) {
         super(props)
 
-        this.state = { currentNode: null, currentFrame: null };
+        this.state = { currentNode: null, currentFrame: null, currentNodePort: null };
     }
 
     componentDidMount() {
         this.props.globalState.onSelectionChangedObservable.add(selection => {
             if (selection instanceof GraphNode) {
-                this.setState({ currentNode: selection, currentFrame: null });
+                this.setState({ currentNode: selection, currentFrame: null, currentNodePort: null });
             } else if (selection instanceof GraphFrame) {
-                this.setState({ currentNode: null, currentFrame: selection });
+                this.setState({ currentNode: null, currentFrame: selection, currentNodePort: null });
+            } else if(selection instanceof NodePort) {
+                this.setState({ currentNode: null, currentFrame: null, currentNodePort: selection });
             } else {
-                this.setState({ currentNode: null, currentFrame: null });
+                this.setState({ currentNode: null, currentFrame: null, currentNodePort: null });
             }
         });
 
@@ -171,6 +175,12 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
             );
         }
 
+        if (this.state.currentNodePort) {
+            return (
+                <NodePortPropertyTabComponent globalState={this.props.globalState} nodePort={this.state.currentNodePort}/>
+            );
+        }
+
         let gridSize = DataStorage.ReadNumber("GridSize", 20);
 
         return (

+ 11 - 2
nodeEditor/src/diagram/graphCanvas.tsx

@@ -14,6 +14,7 @@ import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { DataStorage } from 'babylonjs/Misc/dataStorage';
 import { GraphFrame } from './graphFrame';
 import { IEditorData } from '../nodeLocationInfo';
+import { Observable } from 'babylonjs';
 
 require("./graphCanvas.scss");
 
@@ -50,8 +51,7 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
     private _gridSize = 20;
     private _selectionBox: Nullable<HTMLDivElement> = null;   
     private _selectedFrame: Nullable<GraphFrame> = null;   
-    private _frameCandidate: Nullable<HTMLDivElement> = null;  
-
+    private _frameCandidate: Nullable<HTMLDivElement> = null;
     private _frames: GraphFrame[] = [];
 
     private _altKeyIsPressed = false;
@@ -186,6 +186,11 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
             this._candidatePort = port;
         });
 
+        props.globalState.onFrameNodeMoveUpObserver.add((nodePort: NodePort) => {
+            const frame = this._frames.find(frame => frame.id == nodePort.frameId);
+            frame?.moveFrameNodeUp(nodePort);
+        });
+
         props.globalState.onGridSizeChanged.add(() => {
             this.gridSize = DataStorage.ReadNumber("GridSize", 20);
         });
@@ -584,6 +589,10 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
             if (this._candidateLinkedHasMoved) {
                 this.processCandidatePort();          
                 this.props.globalState.onCandidateLinkMoved.notifyObservers(null);
+            } else { // is a click event on NodePort
+                if(this._candidateLink.portA.frameId !== null) { //only on Frame Ports
+                    this.props.globalState.onSelectionChangedObservable.notifyObservers(this._candidateLink.portA);
+                }
             }
             this._candidateLink.dispose();
             this._candidateLink = null;

+ 35 - 5
nodeEditor/src/diagram/graphFrame.ts

@@ -47,8 +47,8 @@ export class GraphFrame {
     private _mouseStartPointY: Nullable<number> = null;
     private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame>>>;
     private _isCollapsed = false;
-    private _ports: NodePort[] = [];
-    private _controlledPorts: NodePort[] = [];
+    private _ports: NodePort[] = []; // Ports on Outside of Frame
+    private _controlledPorts: NodePort[] = []; // Ports on Nodes that are shown on outside of frame
     private _id: number;
     private _comments: string;
     private _frameIsResizing: boolean;
@@ -72,7 +72,7 @@ export class GraphFrame {
     }
 
     private _createInputPort(port: NodePort, node: GraphNode) {
-        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._inputPortContainer, null, this._ownerCanvas.globalState)
+        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._inputPortContainer, null, this._ownerCanvas.globalState, true, this.id)
         this._ports.push(localPort);
 
         port.delegatedPort = localPort;
@@ -105,7 +105,7 @@ export class GraphFrame {
 
                                 if (!portAdded) {
                                     portAdded = true;
-                                    localPort = NodePort.CreatePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState);
+                                    localPort = NodePort.CreatePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState, true, this.id);
                                     this._ports.push(localPort);
                                 } else {
                                     localPort = this._ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
@@ -117,7 +117,7 @@ export class GraphFrame {
                             }
                         }
                     } else {
-                        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState)
+                        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState, true, this.id)
                         this._ports.push(localPort);
                         port.delegatedPort = localPort;
                         this._controlledPorts.push(port);
@@ -481,6 +481,36 @@ export class GraphFrame {
         this.y = this._ownerCanvas.getGridPosition(this.y);   
     }
 
+    public moveFrameNodeUp(nodePort: NodePort){
+        console.log('moving node up: ', nodePort.portLabel);
+        if(nodePort.isInput) {
+            if(this._inputPortContainer.children.length < 2) {
+                return;
+            }
+            const elementsArray = Array.from(this._inputPortContainer.children);
+            const indexInContainer = (elementsArray as HTMLElement[]).findIndex(elem => elem.dataset.blockId === `${nodePort.node.block.uniqueId}`)
+            if(indexInContainer === 0){
+                return;
+            }
+            var b = elementsArray;
+            const elemA = elementsArray[indexInContainer];
+            const elemB =  elementsArray[indexInContainer -1];
+            
+        } else {
+            if(this._outputPortContainer.children.length < 2) {
+                return;
+            }
+            const elementsArray = Array.from(this._inputPortContainer.children);
+            console.log(elementsArray)
+        }
+
+    }
+    
+    public moveFrameNodeDown(blockUniqueId: number){
+        console.log('moving block down: ', blockUniqueId)
+        
+    }
+
     private _onDown(evt: PointerEvent) {
         evt.stopPropagation();
 

+ 2 - 2
nodeEditor/src/diagram/graphNode.ts

@@ -407,11 +407,11 @@ export class GraphNode {
 
         // Connections
         for (var input of this.block.inputs) {
-            this._inputPorts.push(NodePort.CreatePortElement(input,  this, this._inputsContainer, this._displayManager, this._globalState));
+            this._inputPorts.push(NodePort.CreatePortElement(input,  this, this._inputsContainer, this._displayManager, this._globalState, false, null));
         }
 
         for (var output of this.block.outputs) {
-            this._outputPorts.push(NodePort.CreatePortElement(output,  this, this._outputsContainer, this._displayManager, this._globalState));
+            this._outputPorts.push(NodePort.CreatePortElement(output,  this, this._outputsContainer, this._displayManager, this._globalState, false, null));
         }
 
         this.refresh();

+ 22 - 4
nodeEditor/src/diagram/nodePort.ts

@@ -8,13 +8,14 @@ import { Vector2 } from 'babylonjs/Maths/math.vector';
 import { IDisplayManager } from './display/displayManager';
 import { GraphNode } from './graphNode';
 
-
 export class NodePort {
     private _element: HTMLDivElement;
     private _img: HTMLImageElement;
     private _globalState: GlobalState;
     private _onCandidateLinkMovedObserver: Nullable<Observer<Nullable<Vector2>>>;
     private _portLabel: Element;
+    private _frameId: Nullable<number>
+    private _isInput: boolean;
 
     public delegatedPort: Nullable<NodePort> = null;
 
@@ -26,6 +27,14 @@ export class NodePort {
         return this._element;
     }
 
+    public get frameId() {
+        return this._frameId;
+    }
+
+    public get isInput() {
+        return this._isInput;
+    }
+
     public get portLabel() {
         return this._portLabel.innerHTML;
     }
@@ -58,13 +67,20 @@ export class NodePort {
         }
     }
 
-    public constructor(portContainer: HTMLElement, public connectionPoint: NodeMaterialConnectionPoint, public node: GraphNode, globalState: GlobalState) {
+    private _onSelection(evt: PointerEvent) {
+        console.log('nodePort._onSelection()')
+        // this._globalState.onSelectionChangedObservable.notifyObservers(this);
+    }
+
+    public constructor(portContainer: HTMLElement, public connectionPoint: NodeMaterialConnectionPoint, public node: GraphNode, globalState: GlobalState, isInput: boolean, frameId: Nullable<number>) {
         this._element = portContainer.ownerDocument!.createElement("div");
         this._element.classList.add("port");
         portContainer.appendChild(this._element);
         this._globalState = globalState;
 
         this._portLabel = portContainer.children[0];
+        this._frameId = frameId
+        this._isInput = isInput;
 
         this._img = portContainer.ownerDocument!.createElement("img");
         this._element.appendChild(this._img );
@@ -75,6 +91,7 @@ export class NodePort {
         this._element.ondragstart= () => false;
 
         this._onCandidateLinkMovedObserver = globalState.onCandidateLinkMoved.add(coords => {
+            console.log('candidate link moved')
             const rect = this._element.getBoundingClientRect();
 
             if (!coords || rect.left > coords.x || rect.right < coords.x || rect.top > coords.y || rect.bottom < coords.y) {
@@ -94,11 +111,12 @@ export class NodePort {
     }
 
     public static CreatePortElement(connectionPoint: NodeMaterialConnectionPoint, node: GraphNode, root: HTMLElement, 
-            displayManager: Nullable<IDisplayManager>, globalState: GlobalState) {
+            displayManager: Nullable<IDisplayManager>, globalState: GlobalState, isInput: boolean,  frameId:Nullable<number> = null) {
         let portContainer = root.ownerDocument!.createElement("div");
         let block = connectionPoint.ownerBlock;
 
         portContainer.classList.add("portLine");
+        portContainer.dataset.blockId = `${node.block.uniqueId}`;
         root.appendChild(portContainer);
 
         if (!displayManager || displayManager.shouldDisplayPortLabels(block)) {
@@ -108,6 +126,6 @@ export class NodePort {
             portContainer.appendChild(portLabel);
         }
     
-        return new NodePort(portContainer, connectionPoint, node, globalState);
+        return new NodePort(portContainer, connectionPoint, node, globalState, isInput, frameId);
     }
 }

+ 1 - 7
nodeEditor/src/diagram/properties/framePropertyComponent.tsx

@@ -47,13 +47,7 @@ export class FramePropertyTabComponent extends React.Component<IFramePropertyTab
                 <LineContainerComponent title="GENERAL">
                     <TextInputLineComponent globalState={this.props.globalState} label="Name" propertyName="name" target={this.props.frame} />
                     <Color3LineComponent globalState={this.props.globalState} label="Color" target={this.props.frame} propertyName="color"></Color3LineComponent>
-                    <TextInputLineComponent globalState={this.props.globalState} label="Comments" propertyName="comments" target={this.props.frame}
-                    />
-                    {
-                        this.props.frame.ports && this.props.frame.ports.map((port: NodePort) => 
-                        <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portLabel" target={port}/>
-                        )
-                    }
+                    <TextInputLineComponent globalState={this.props.globalState} label="Comments" propertyName="comments" target={this.props.frame}/>
                     {
                         !this.props.frame.isCollapsed &&
                         <ButtonLineComponent label="Collapse" onClick={() => {

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

@@ -0,0 +1,90 @@
+
+import * as React from "react";
+import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
+import { GraphFrame } from '../graphFrame';
+import { GlobalState } from '../../globalState';
+import { Color3LineComponent } from '../../sharedComponents/color3LineComponent';
+import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
+import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
+import { Nullable } from 'babylonjs/types';
+import { Observer } from 'babylonjs/Misc/observable';
+import { NodePort } from '../nodePort';
+
+export interface INodePortPropertyTabComponentProps {
+    globalState: GlobalState
+    nodePort: NodePort;
+}
+
+export class NodePortPropertyTabComponent extends React.Component<INodePortPropertyTabComponentProps> {
+    private onFrameExpandStateChangedObserver: Nullable<Observer<GraphFrame>>;
+
+    constructor(props: INodePortPropertyTabComponentProps) {
+        super(props)
+    }
+
+
+    // componentDidMount() {
+    //     this.onFrameExpandStateChangedObserver = this.props.frame.onExpandStateChanged.add(() => this.forceUpdate());
+    // }
+
+    // componentWillUnmount() {
+    //     if (this.onFrameExpandStateChangedObserver) {
+    //         this.props.frame.onExpandStateChanged.remove(this.onFrameExpandStateChangedObserver);
+    //         this.onFrameExpandStateChangedObserver = null;
+    //     }
+    // }    
+
+    render() {      
+        return (
+            <div id="propertyTab">
+            <div id="header">
+                <img id="logo" src="https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" />
+                <div id="title">
+                    NODE MATERIAL EDITOR
+                </div>
+            </div>
+            <div>
+                <LineContainerComponent title="GENERAL">
+                    <div>
+                        NodePortPropertyComponent
+                    </div>
+                    <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portLabel" target={this.props.nodePort}/>
+                    <ButtonLineComponent label="Move Node Up" onClick={() => {
+                                console.log('click on up')
+                                console.log(this.props.nodePort.frameId)
+                                console.log(this.props.nodePort.node.block.uniqueId)
+                                this.props.globalState.onFrameNodeMoveUpObserver.notifyObservers(this.props.nodePort);
+                            }} />
+
+                    <ButtonLineComponent label="Move Node Down" onClick={() => {
+                                console.log('click on down')
+                            }} />
+                    {/* <TextInputLineComponent globalState={this.props.globalState} label="Name" prop–ertyName="name" target={this.props.frame} /> */}
+                    {/* <Color3LineComponent globalState={this.props.globalState} label="Color" target={this.props.frame} propertyName="color"></Color3LineComponent>
+                    <TextInputLineComponent globalState={this.props.globalState} label="Comments" propertyName="comments" target={this.props.frame}
+                    />
+                    {
+                        this.props.frame.ports && this.props.frame.ports.map((port: NodePort) => 
+                        )
+                    }
+                    {
+                        !this.props.frame.isCollapsed &&
+                        <ButtonLineComponent label="Collapse" onClick={() => {
+                                this.props.frame!.isCollapsed = true;
+                            }} />
+                    }
+                    {
+                        this.props.frame.isCollapsed &&
+                        <ButtonLineComponent label="Expand" onClick={() => {
+                                this.props.frame!.isCollapsed = false;
+                            }} />
+                    }
+                    {/* <ButtonLineComponent label="Export" onClick={() => {
+                                this.state.currentFrame!.export();
+                            }} /> */} 
+                </LineContainerComponent>
+            </div>
+        </div>
+        );
+    }
+}

+ 2 - 1
nodeEditor/src/globalState.ts

@@ -17,7 +17,7 @@ export class GlobalState {
     hostElement: HTMLElement;
     hostDocument: HTMLDocument;
     hostWindow: Window;
-    onSelectionChangedObservable = new Observable<Nullable<GraphNode | NodeLink | GraphFrame>>();
+    onSelectionChangedObservable = new Observable<Nullable<GraphNode | NodeLink | GraphFrame | NodePort>>();
     onRebuildRequiredObservable = new Observable<void>();
     onBuiltObservable = new Observable<void>();
     onResetRequiredObservable = new Observable<void>();
@@ -37,6 +37,7 @@ export class GlobalState {
     onSelectionBoxMoved = new Observable<ClientRect | DOMRect>();
     onFrameCreated = new Observable<GraphFrame>();
     onCandidatePortSelected = new Observable<Nullable<NodePort>>();
+    onFrameNodeMoveUpObserver = new Observable<NodePort>();
     onGetNodeFromBlock: (block: NodeMaterialBlock) => GraphNode;
     onGridSizeChanged = new Observable<void>();
     previewMeshType: PreviewMeshType;