public override void OnInspectorGUI() { EditorGUILayout.BeginHorizontal(); editState = (NodeEditorState)GUILayout.SelectionGrid((int)editState,editNames, 1); EditorGUILayout.EndHorizontal(); base.OnInspectorGUI(); }
public void LoadNodeCanvas(string path) { // Else it will be stuck forever NodeEditor.StopTransitioning (canvas); // Load the NodeCanvas canvas = NodeEditorSaveManager.LoadNodeCanvas (path); if (canvas == null) { NewNodeCanvas (); return; } // Load the associated MainEditorState List<NodeEditorState> editorStates = NodeEditorSaveManager.LoadEditorStates (path); if (editorStates.Count == 0) state = ScriptableObject.CreateInstance<NodeEditorState> (); else { state = editorStates.Find (x => x.name == "MainEditorState"); if (state == null) state = editorStates[0]; } state.canvas = canvas; NodeEditor.RecalculateAll (canvas); }
public void NewNodeCanvas() { // New NodeCanvas canvas = ScriptableObject.CreateInstance<NodeCanvas> ();; // New NodeEditorState state = ScriptableObject.CreateInstance<NodeEditorState> (); state.canvas = canvas; state.name = "MainEditorState"; }
public void LoadNodeCanvas (string path) { // Load the NodeCanvas canvas = NodeEditor.LoadNodeCanvas (path); if (canvas == null) canvas = ScriptableObject.CreateInstance<NodeCanvas> (); // Load the associated MainEditorState List<NodeEditorState> editorStates = NodeEditor.LoadEditorStates (path); if (editorStates.Count == 0) state = ScriptableObject.CreateInstance<NodeEditorState> (); else { state = editorStates.Find (x => x.name == "MainEditorState"); if (state == null) state = editorStates[0]; } NodeEditor.RecalculateAll (canvas); }
public override void NodeGUI () { GUILayout.BeginHorizontal (); #if UNITY_EDITOR if (GUILayout.Button (new GUIContent ("Load", "Loads the group from an extern Canvas Asset File."))) { string path = UnityEditor.EditorUtility.OpenFilePanel ("Load Node Canvas", NodeEditor.EditorPath + "Saves/", "asset"); if (!path.Contains (Application.dataPath)) { // TODO: Generic Notification //if (path != String.Empty) //ShowNotification (new GUIContent ("You should select an asset inside your project folder!")); return; } path = path.Replace (Application.dataPath, "Assets"); LoadNodeCanvas (path); //AdoptInputsOutputs (); } if (GUILayout.Button (new GUIContent ("Save", "Saves the group as a new Canvas Asset File"))) { NodeEditor.SaveNodeCanvas (NodeGroupCanvas, UnityEditor.EditorUtility.SaveFilePanelInProject ("Save Group Node Canvas", "Group Canvas", "asset", "", NodeEditor.EditorPath + "Saves/")); } #endif if (GUILayout.Button (new GUIContent ("New Group Canvas", "Creates a new Canvas"))) { NodeGroupCanvas = CreateInstance<NodeCanvas> (); EditorState = CreateInstance<NodeEditorState> (); EditorState.Drawing = Edit; EditorState.name = "GroupNode_EditorState"; Node node = NodeTypes.GetDefaultNode ("exampleNode"); if (node != null) { NodeCanvas prevNodeCanvas = NodeEditor.CurNodeCanvas; NodeEditor.CurNodeCanvas = NodeGroupCanvas; node = node.Create (Vector2.zero); node.InitBase (); NodeEditor.CurNodeCanvas = prevNodeCanvas; } } GUILayout.EndHorizontal (); if (NodeGroupCanvas != null) { foreach (NodeInput input in Inputs) input.DisplayLayout (); foreach (NodeOutput output in Outputs) output.DisplayLayout (); if (!Edit) { if (GUILayout.Button ("Edit Node Canvas")) { Rect = OpenedRect; Edit = true; EditorState.CanvasRect = GUILayoutUtility.GetRect (canvasSize.x, canvasSize.y, GUIStyle.none); EditorState.Drawing = true; } } else { if (GUILayout.Button ("Stop editing Node Canvas")) { NodeRect.position = OpenedRect.position + new Vector2 (canvasSize.x/2 - NodeRect.width/2, 0); Rect = NodeRect; Edit = false; EditorState.Drawing = false; } Rect canvasRect = GUILayoutUtility.GetRect (canvasSize.x, canvasSize.y, new GUILayoutOption[] { GUILayout.ExpandWidth (false) }); if (Event.current.type != EventType.Layout) { EditorState.CanvasRect = canvasRect; Rect canvasControlRect = EditorState.CanvasRect; canvasControlRect.position += Rect.position + ContentOffset; NodeEditor.CurEditorState.IgnoreInput.Add (NodeEditor.CanvasGUIToScreenRect (canvasControlRect)); } NodeEditor.DrawSubCanvas (NodeGroupCanvas, EditorState); GUILayout.BeginArea (new Rect (canvasSize.x + 8, 45, 200, canvasSize.y), GUI.skin.box); GUILayout.Label (new GUIContent ("Node Editor (" + NodeGroupCanvas.name + ")", "The currently opened canvas in the Node Editor")); #if UNITY_EDITOR EditorState.Zoom = UnityEditor.EditorGUILayout.Slider (new GUIContent ("Zoom", "Use the Mousewheel. Seriously."), EditorState.Zoom, 0.6f, 2); #endif GUILayout.EndArea (); // Node is drawn by parent nodeCanvas, usually the mainNodeCanvas, because the zoom feature requires it to be drawn outside of any GUI group } } }
void Hotkeys() { Event current = Event.current; if (!current.alt) { if (current.isKey && current.keyCode == KeyCode.Alpha1) { editState = NodeEditorState.NONE; Repaint(); } if (current.isKey && current.keyCode == KeyCode.Alpha2) { editState = NodeEditorState.ADD; Repaint(); } if (current.isKey && current.keyCode == KeyCode.Alpha3) { editState = NodeEditorState.DELETENODE; Repaint(); } if (current.isKey && current.keyCode == KeyCode.Alpha4) { editState = NodeEditorState.LINK; Repaint(); } if (current.isKey && current.keyCode == KeyCode.Alpha5) { editState = NodeEditorState.UNLINK; Repaint(); } } }
/// <summary> /// Creates and opens a new empty node canvas /// </summary> public void NewNodeCanvas() { // New NodeCanvas mainNodeCanvas = CreateInstance<NodeCanvas> (); mainNodeCanvas.nodes = new List<Node> (); // New NodeEditorState mainEditorState = CreateInstance<NodeEditorState> (); mainEditorState.canvas = mainNodeCanvas; mainEditorState.name = "MainEditorState"; // Set some properties openedCanvas = "New Canvas"; openedCanvasPath = ""; }
public callbackObject(string Message, NodeCanvas nodecanvas, NodeEditorState editorState, Node Node) { message = Message; canvas = nodecanvas; editor = editorState; node = Node; }
/// <summary> /// Returns the node at the position in specified canvas space. /// </summary> public static Node NodeAtPosition(NodeEditorState editorState, NodeCanvas nodecanvas, Vector2 pos) { if (!editorState.canvasRect.Contains (pos)) return null; // Check if we clicked inside a window (or knobSize pixels left or right of it at outputs, for faster knob recognition) float KnobSize = (float)NodeEditor.knobSize/editorState.zoom; if (editorState.activeNode != null) { // active Node is drawn ontop, so we check it first Rect NodeRect = new Rect (GUIToScreenRect (editorState.activeNode.rect)); NodeRect = new Rect (NodeRect.x - KnobSize, NodeRect.y, NodeRect.width + KnobSize*2, NodeRect.height); if (NodeRect.Contains (pos)) return editorState.activeNode; } for (int nodeCnt = nodecanvas.nodes.Count-1; nodeCnt >= 0; nodeCnt--) { // checked from top to bottom because of the render order Rect NodeRect = new Rect (GUIToScreenRect (nodecanvas.nodes [nodeCnt].rect)); NodeRect = new Rect (NodeRect.x - KnobSize, NodeRect.y, NodeRect.width + KnobSize*2, NodeRect.height); if (NodeRect.Contains (pos)) return nodecanvas.nodes [nodeCnt]; } return null; }
/// <summary> /// Draws the Node Canvas on the screen in the rect specified by editorState. Has to be called out of any GUI Group or area because of zooming. /// </summary> public static void DrawCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState) { if (!editorState.drawing) return; curNodeCanvas = nodeCanvas; curEditorState = editorState; // if (curEditorState.parent != null) // curEditorState.canvasRect.position += curEditorState.parent.zoomPanAdjust; if (Event.current.type == EventType.Repaint) { // Draw Background when Repainting GUI.BeginClip (curEditorState.canvasRect); float width = Background.width / curEditorState.zoom; float height = Background.height / curEditorState.zoom; Vector2 offset = new Vector2 ((curEditorState.panOffset.x / curEditorState.zoom)%width - width, (curEditorState.panOffset.y / curEditorState.zoom)%height - height); int tileX = Mathf.CeilToInt ((curEditorState.canvasRect.width + (width - offset.x)) / width); int tileY = Mathf.CeilToInt ((curEditorState.canvasRect.height + (height - offset.y)) / height); for (int x = 0; x < tileX; x++) { for (int y = 0; y < tileY; y++) { Rect texRect = new Rect (offset.x + x*width, offset.y + y*height, width, height); GUI.DrawTexture (texRect, Background); } } GUI.EndClip (); } // if (curEditorState.parent != null) // curEditorState.canvasRect.position -= curEditorState.parent.zoomPanAdjust - curEditorState.parent.zoomPos; // Fetch all nested nodeEditors and set their canvasRects to be ignored by input, // so it can be handled later, and note it down, as it will be drawn later ontop List<Rect> ignoreInput = new List<Rect> (); for (int childCnt = 0; childCnt < curEditorState.childs.Count; childCnt++) { if (curEditorState.childs [childCnt].drawing) { NodeEditorState nestedEditor = curEditorState.childs [childCnt]; ignoreInput.Add (GUIToScreenRect (nestedEditor.canvasRect)); } } // Check the inputs InputEvents (ignoreInput); // We want to scale our nodes, but as GUI.matrix also scales our widnow's clipping group, // we have to scale it up first to receive a correct one as a result #region Scale Setup // End the default clipping group GUI.EndGroup (); // The Rect of the new clipping group to draw our nodes in Rect ScaledCanvasRect = ScaleRect (curEditorState.canvasRect, curEditorState.zoomPos + curEditorState.canvasRect.position, new Vector2 (curEditorState.zoom, curEditorState.zoom)); ScaledCanvasRect.y += 23; // Header tab height if (curNodeCanvas != NodeEditorWindow.mainNodeCanvas) GUI.DrawTexture (ScaledCanvasRect, Background); // Now continue drawing using the new clipping group GUI.BeginGroup (ScaledCanvasRect); ScaledCanvasRect.position = Vector2.zero; // Adjust because we entered the new group // Because I currently found no way to actually scale to the center of the window rather than (0, 0), // I'm going to cheat and just pan it accordingly to let it appear as if it would scroll to the center // Note, due to that, other controls are still scaled to (0, 0) curEditorState.zoomPanAdjust = ScaledCanvasRect.center - curEditorState.canvasRect.size/2 + curEditorState.zoomPos; // Take a matrix backup to restore back later on Matrix4x4 GUIMatrix = GUI.matrix; // Scale GUI.matrix. After that we have the correct clipping group again. GUIUtility.ScaleAroundPivot (new Vector2 (1/curEditorState.zoom, 1/curEditorState.zoom), curEditorState.zoomPanAdjust); #endregion // Some features which require drawing (zoomed) if (curEditorState.navigate) { // Draw a curve to the origin/active node for orientation purposes DrawNodeCurve ((curEditorState.activeNode != null? curEditorState.activeNode.rect.center : curEditorState.panOffset), ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.black); NodeEditorWindow.editor.Repaint (); } if (curEditorState.connectOutput != null) { // Draw the currently drawn connection DrawNodeCurve (curEditorState.connectOutput.GetGUIKnob ().center, ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom, ConnectionTypes.types [curEditorState.connectOutput.type].col); NodeEditorWindow.editor.Repaint (); } if (curNodeCanvas != NodeEditorWindow.mainNodeCanvas) return; // Draw the nodes for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { Node node = curNodeCanvas.nodes [nodeCnt]; //if (node != curEditorState.activeNode) NodeEditor.DrawNode (node); } // Draw their connectors; Seperated because of render order for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) curNodeCanvas.nodes [nodeCnt].DrawConnections (); for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) curNodeCanvas.nodes [nodeCnt].DrawKnobs (); // Draw the active Node ontop // if (editorState.activeNode != null) // NodeEditor.DrawNode (curEditorState.activeNode); // Draw any node groups out there. Has to be drawn here, because they still need to scale according to their parents, but they mustn't be drawn inside a GUI group for (int editorCnt = 0; editorCnt < curEditorState.childs.Count; editorCnt++) { if (curEditorState.childs [editorCnt].drawing) { NodeEditorState nestedEditor = curEditorState.childs [editorCnt]; nestedEditor.canvasRect.position += curEditorState.zoomPanAdjust; //GUI.DrawTexture (nestedEditor.canvasRect, Background); DrawCanvas (nestedEditor.canvas, nestedEditor); nestedEditor.canvasRect.position -= curEditorState.zoomPanAdjust; } } curNodeCanvas = nodeCanvas; curEditorState = editorState; // End scaling group // Set default matrix and clipping group for the rest GUI.matrix = GUIMatrix; GUI.EndGroup (); if (curNodeCanvas.parent == null) GUI.BeginGroup (new Rect (0, 23, NodeEditorWindow.editor.position.width, NodeEditorWindow.editor.position.height)); else { Rect parentGroupRect = ScaleRect (curEditorState.parent.canvasRect, curEditorState.parent.zoomPos + curEditorState.parent.canvasRect.position, new Vector2 (curEditorState.parent.zoom, curEditorState.parent.zoom)); parentGroupRect.y += 23; // Header tab height GUI.BeginGroup (parentGroupRect); } // Check events with less priority than node GUI controls LateEvents (ignoreInput); }
/// <summary> /// Context Click selection. Here you'll need to register your own using a string identifier /// </summary> public static void ContextCallback(object obj) { callbackObject cbObj = obj as callbackObject; curNodeCanvas = cbObj.canvas; curEditorState = cbObj.editor; switch (cbObj.message) { case "deleteNode": if (cbObj.node != null) cbObj.node.Delete (); break; case "duplicateNode": if (cbObj.node != null) { ContextCallback (new callbackObject (cbObj.node.GetID, curNodeCanvas, curEditorState)); Node duplicatedNode = curNodeCanvas.nodes [curNodeCanvas.nodes.Count-1]; curEditorState.activeNode = duplicatedNode; curEditorState.dragNode = true; } break; default: foreach (Node node in NodeTypes.nodes.Keys) { if (node.GetID == cbObj.message) { var newNode = node.Create (ScreenToGUIPos (mousePos)); newNode.InitBase(); // If nodeOutput is defined, link it to the first input of the same type if(cbObj.nodeOutput != null) { foreach (var input in newNode.Inputs) { if (input.type == cbObj.nodeOutput.type) { if (Node.CanApplyConnection (cbObj.nodeOutput, input)) { // If it can connect (type is equals, it does not cause recursion, ...) Node.ApplyConnection (cbObj.nodeOutput, input); break; } } } } break; } } break; } }
public void NewNodeCanvas() { // Else it will be stuck forever NodeEditor.StopTransitioning (canvas); canvas = ScriptableObject.CreateInstance<NodeCanvas> (); state = ScriptableObject.CreateInstance<NodeEditorState> (); state.canvas = canvas; state.name = "MainEditorState"; }
public override void NodeGUI () { GUILayout.BeginHorizontal (); #if UNITY_EDITOR if (GUILayout.Button (new GUIContent ("Load", "Loads the group from an extern Canvas Asset File."))) { string path = UnityEditor.EditorUtility.OpenFilePanel ("Load Node Canvas", NodeEditor.editorPath + "Saves/", "asset"); if (!path.Contains (Application.dataPath)) { // TODO: Generic Notification //if (path != String.Empty) //ShowNotification (new GUIContent ("You should select an asset inside your project folder!")); return; } path = path.Replace (Application.dataPath, "Assets"); nodeGroupCanvas = NodeEditor.LoadNodeCanvas (path); editorState = NodeEditor.LoadEditorStates (path) [0]; editorState.drawing = edit; if (nodeGroupCanvas != null) { // Set the name string[] folders = path.Split (new char[] {'/'}, StringSplitOptions.None); string canvasName = folders [folders.Length-1]; if (canvasName.EndsWith (".asset")) canvasName = canvasName.Remove (canvasName.Length-6); name = canvasName; } else name = "Node Group"; //AdoptInputsOutputs (); } if (GUILayout.Button (new GUIContent ("Save", "Saves the group as a new Canvas Asset File"))) { NodeEditor.SaveNodeCanvas (nodeGroupCanvas, UnityEditor.EditorUtility.SaveFilePanelInProject ("Save Group Node Canvas", "Group Canvas", "asset", "Saving to a file is only needed once.", NodeEditor.editorPath + "Saves/")); } #endif if (GUILayout.Button (new GUIContent ("New Group Canvas", "Creates a new Canvas (remember to save the previous one to a referenced Canvas Asset File at least once before! Else it'll be lost!)"))) { nodeGroupCanvas = CreateInstance<NodeCanvas> (); editorState = CreateInstance<NodeEditorState> (); editorState.drawing = edit; editorState.name = "GroupNode_EditorState"; } GUILayout.EndHorizontal (); foreach (NodeInput input in Inputs) input.DisplayLayout (); foreach (NodeOutput output in Outputs) output.DisplayLayout (); if (!edit && nodeGroupCanvas != null) { if (GUILayout.Button ("Edit Node Canvas")) { rect = openedRect; edit = true; editorState.canvasRect = GUILayoutUtility.GetRect (canvasSize.x, canvasSize.y, GUIStyle.none); editorState.drawing = true; } } else if (nodeGroupCanvas != null) { if (GUILayout.Button ("Stop editing Node Canvas")) { nodeRect.position = openedRect.position + new Vector2 (canvasSize.x/2 - nodeRect.width/2, 0); rect = nodeRect; edit = false; editorState.drawing = false; } editorState.canvasRect = GUILayoutUtility.GetRect (canvasSize.x - 200, canvasSize.y, new GUILayoutOption[] { GUILayout.ExpandWidth (false) }); NodeEditor.curEditorState.ignoreInput.Add (NodeEditor.GUIToScreenRect (editorState.canvasRect)); NodeEditor.DrawSubCanvas (nodeGroupCanvas, editorState); GUILayout.BeginArea (new Rect (canvasSize.x - 200 + 2, editorState.canvasRect.y + 42, 200, canvasSize.y), GUI.skin.box); GUILayout.Label (new GUIContent ("Node Editor (" + nodeGroupCanvas.name + ")", "The currently opened canvas in the Node Editor")); GUILayout.EndArea (); // Node is drawn by parent nodeCanvas, usually the mainNodeCanvas, because the zoom feature requires it to be drawn outside of any GUI group } }
public override void NodeGUI() { GUILayout.BeginHorizontal (); if (GUILayout.Button (new GUIContent ("Load", "Loads the group from an extern Canvas Asset File."))) { #if UNITY_EDITOR string path = UnityEditor.EditorUtility.OpenFilePanel ("Load Node Canvas", NodeEditor.editorPath + "Saves/", "asset"); if (!path.Contains (Application.dataPath)) { if (path != String.Empty) NodeEditorWindow.editor.ShowNotification (new GUIContent ("You should select an asset inside your project folder!")); return; } path = path.Replace (Application.dataPath, "Assets"); if (nodeGroupCanvas != null) NodeEditor.curNodeCanvas.childs.Remove (nodeGroupCanvas); nodeGroupCanvas = NodeEditor.LoadNodeCanvas (path); nodeGroupCanvas.parent = NodeEditor.curNodeCanvas; NodeEditor.curNodeCanvas.childs.Add (nodeGroupCanvas); if (editorState != null) NodeEditor.curEditorState.childs.Remove (editorState); editorState = NodeEditor.LoadEditorStates (path) [0]; editorState.parent = NodeEditor.curEditorState; editorState.drawing = edit; NodeEditor.curEditorState.childs.Add (editorState); if (nodeGroupCanvas != null) { // Set the name string[] folders = path.Split (new char[] {'/'}, StringSplitOptions.None); string canvasName = folders [folders.Length-1]; if (canvasName.EndsWith (".asset")) canvasName = canvasName.Remove (canvasName.Length-6); name = canvasName; } else name = "Node Group"; //AdoptInputsOutputs (); #endif } if (GUILayout.Button (new GUIContent ("Save", "Saves the group as a new Canvas Asset File"))) { #if UNITY_EDITOR NodeEditor.SaveNodeCanvas (nodeGroupCanvas, UnityEditor.EditorUtility.SaveFilePanelInProject ("Save Group Node Canvas", "Group Canvas", "asset", "Saving to a file is only needed once.", NodeEditor.editorPath + "Saves/")); #endif } if (GUILayout.Button (new GUIContent ("New Group Canvas", "Creates a new Canvas (remember to save the previous one to a referenced Canvas Asset File at least once before! Else it'll be lost!)"))) { if (nodeGroupCanvas != null) NodeEditor.curNodeCanvas.childs.Remove (nodeGroupCanvas); nodeGroupCanvas = CreateInstance<NodeCanvas> (); nodeGroupCanvas.parent = NodeEditor.curNodeCanvas; NodeEditor.curNodeCanvas.childs.Add (nodeGroupCanvas); if (editorState != null) NodeEditor.curEditorState.childs.Remove (editorState); editorState = CreateInstance<NodeEditorState> (); editorState.parent = NodeEditor.curEditorState; editorState.drawing = edit; NodeEditor.curEditorState.childs.Add (editorState); editorState.name = "GroupNode_EditorState"; } GUILayout.EndHorizontal (); foreach (NodeInput input in Inputs) input.DisplayLayout (); foreach (NodeOutput output in Outputs) output.DisplayLayout (); if (!edit && nodeGroupCanvas != null) { if (GUILayout.Button ("Edit Node Canvas")) { rect = openedRect; edit = true; editorState.canvasRect = canvasRect; editorState.drawing = true; } } else if (nodeGroupCanvas != null) { editorState.canvasRect = canvasRect; if (GUILayout.Button ("Stop editing Node Canvas")) { nodeRect.position = openedRect.position + new Vector2 (canvasSize.x/2 - nodeRect.width/2, 0); rect = nodeRect; edit = false; editorState.drawing = false; } // Node is drawn by parent nodeCanvas, usually the mainNodeCanvas, because the zoom feature requires it to be drawn outside of any GUI group } }
/// <summary> /// Converts the simplified CanvasData back to a proper NodeCanvas /// </summary> internal static NodeCanvas ConvertToNodeCanvas(CanvasData canvasData) { if (canvasData == null) { return(null); } NodeCanvas nodeCanvas = NodeCanvas.CreateCanvas(canvasData.type); nodeCanvas.name = nodeCanvas.saveName = canvasData.name; nodeCanvas.nodes.Clear(); NodeEditor.BeginEditingCanvas(nodeCanvas); foreach (NodeData nodeData in canvasData.nodes.Values) { // Read all nodes Node node = Node.Create(nodeData.typeID, nodeData.nodePos, NodeEditor.curNodeCanvas, null, true, false); if (!string.IsNullOrEmpty(nodeData.name)) { node.name = nodeData.name; } if (node == null) { continue; } foreach (ConnectionPortDeclaration portDecl in ConnectionPortManager.GetPortDeclarationEnumerator(node)) { // Find stored ports for each node port declaration PortData portData = nodeData.connectionPorts.Find((PortData data) => data.name == portDecl.portField.Name); if (portData != null) // Stored port has been found, record { portData.port = (ConnectionPort)portDecl.portField.GetValue(node); } } foreach (PortData portData in nodeData.connectionPorts.Where(port => port.dynamic)) { // Find stored dynamic connection ports if (portData.port != null) // Stored port has been recreated { portData.port.body = node; node.dynamicConnectionPorts.Add(portData.port); } } foreach (VariableData varData in nodeData.variables) { // Restore stored variable to node FieldInfo field = node.GetType().GetField(varData.name); if (field != null) { field.SetValue(node, varData.refObject != null ? varData.refObject.data : varData.value); } } node.OnCreate(); } foreach (ConnectionData conData in canvasData.connections) { // Restore all connections if (conData.port1.port == null || conData.port2.port == null) { // Not all ports where saved in canvasData Debug.Log("Incomplete connection " + conData.port1.name + " and " + conData.port2.name + "!"); continue; } conData.port1.port.TryApplyConnection(conData.port2.port, true); } foreach (GroupData groupData in canvasData.groups) { // Recreate groups NodeGroup group = new NodeGroup(); group.title = groupData.name; group.rect = groupData.rect; group.color = groupData.color; nodeCanvas.groups.Add(group); } nodeCanvas.editorStates = new NodeEditorState[canvasData.editorStates.Length]; for (int i = 0; i < canvasData.editorStates.Length; i++) { // Read all editorStates EditorStateData stateData = canvasData.editorStates[i]; NodeEditorState state = ScriptableObject.CreateInstance <NodeEditorState>(); state.selectedNode = stateData.selectedNode == null ? null : canvasData.FindNode(stateData.selectedNode.nodeID).node; state.panOffset = stateData.panOffset; state.zoom = stateData.zoom; state.canvas = nodeCanvas; state.name = "EditorState"; nodeCanvas.editorStates[i] = state; } NodeEditor.EndEditingCanvas(); return(nodeCanvas); }
public callbackObject(string Message, NodeCanvas nodecanvas, NodeEditorState editorState) { message = Message; canvas = nodecanvas; editor = editorState; node = null; nodeOutput = null; }
/// <summary> /// Context Click selection. Here you'll need to register your own using a string identifier /// </summary> public static void ContextCallback(object obj) { callbackObject cbObj = obj as callbackObject; curNodeCanvas = cbObj.canvas; curEditorState = cbObj.editor; switch (cbObj.message) { case "deleteNode": if (cbObj.node != null) cbObj.node.Delete (); break; case "duplicateNode": if (cbObj.node != null) { ContextCallback (new callbackObject (cbObj.node.GetID, curNodeCanvas, curEditorState)); Node duplicatedNode = curNodeCanvas.nodes [curNodeCanvas.nodes.Count-1]; curEditorState.activeNode = duplicatedNode; curEditorState.dragNode = true; } break; default: foreach (Node node in NodeTypes.nodes) { if (node.GetID == cbObj.message) { node.Create (ScreenToGUIPos (mousePos)).InitBase (); break; } } break; } }
public override void NodeGUI() { GUILayout.BeginHorizontal(); if (GUILayout.Button(new GUIContent("Load", "Loads the group from an extern Canvas Asset File."))) { #if UNITY_EDITOR string path = UnityEditor.EditorUtility.OpenFilePanel("Load Node Canvas", NodeEditor.editorPath + "Saves/", "asset"); if (!path.Contains(Application.dataPath)) { if (path != String.Empty) { NodeEditorWindow.editor.ShowNotification(new GUIContent("You should select an asset inside your project folder!")); } return; } path = path.Replace(Application.dataPath, "Assets"); if (nodeGroupCanvas != null) { NodeEditor.curNodeCanvas.childs.Remove(nodeGroupCanvas); } nodeGroupCanvas = NodeEditor.LoadNodeCanvas(path); nodeGroupCanvas.parent = NodeEditor.curNodeCanvas; NodeEditor.curNodeCanvas.childs.Add(nodeGroupCanvas); if (editorState != null) { NodeEditor.curEditorState.childs.Remove(editorState); } editorState = NodeEditor.LoadEditorStates(path) [0]; editorState.parent = NodeEditor.curEditorState; editorState.drawing = edit; NodeEditor.curEditorState.childs.Add(editorState); if (nodeGroupCanvas != null) { // Set the name string[] folders = path.Split(new char[] { '/' }, StringSplitOptions.None); string canvasName = folders [folders.Length - 1]; if (canvasName.EndsWith(".asset")) { canvasName = canvasName.Remove(canvasName.Length - 6); } name = canvasName; } else { name = "Node Group"; } //AdoptInputsOutputs (); #endif } if (GUILayout.Button(new GUIContent("Save", "Saves the group as a new Canvas Asset File"))) { #if UNITY_EDITOR NodeEditor.SaveNodeCanvas(nodeGroupCanvas, UnityEditor.EditorUtility.SaveFilePanelInProject("Save Group Node Canvas", "Group Canvas", "asset", "Saving to a file is only needed once.", NodeEditor.editorPath + "Saves/")); #endif } if (GUILayout.Button(new GUIContent("New Group Canvas", "Creates a new Canvas (remember to save the previous one to a referenced Canvas Asset File at least once before! Else it'll be lost!)"))) { if (nodeGroupCanvas != null) { NodeEditor.curNodeCanvas.childs.Remove(nodeGroupCanvas); } nodeGroupCanvas = CreateInstance <NodeCanvas> (); nodeGroupCanvas.parent = NodeEditor.curNodeCanvas; NodeEditor.curNodeCanvas.childs.Add(nodeGroupCanvas); if (editorState != null) { NodeEditor.curEditorState.childs.Remove(editorState); } editorState = CreateInstance <NodeEditorState> (); editorState.parent = NodeEditor.curEditorState; editorState.drawing = edit; NodeEditor.curEditorState.childs.Add(editorState); editorState.name = "GroupNode_EditorState"; } GUILayout.EndHorizontal(); foreach (NodeInput input in Inputs) { input.DisplayLayout(); } foreach (NodeOutput output in Outputs) { output.DisplayLayout(); } if (!edit && nodeGroupCanvas != null) { if (GUILayout.Button("Edit Node Canvas")) { rect = openedRect; edit = true; editorState.canvasRect = canvasRect; editorState.drawing = true; } } else if (nodeGroupCanvas != null) { editorState.canvasRect = canvasRect; if (GUILayout.Button("Stop editing Node Canvas")) { nodeRect.position = openedRect.position + new Vector2(canvasSize.x / 2 - nodeRect.width / 2, 0); rect = nodeRect; edit = false; editorState.drawing = false; } // Node is drawn by parent nodeCanvas, usually the mainNodeCanvas, because the zoom feature requires it to be drawn outside of any GUI group } }
/// <summary> /// Transforms the Rect in GUI space into Screen space /// </summary> public static Rect GUIToScreenRect(NodeEditorState editorState, Rect rect) { rect.position += editorState.zoomPos; rect = ScaleRect (rect, editorState.zoomPos, new Vector2 (1/editorState.zoom, 1/editorState.zoom)); rect.position += editorState.canvasRect.position; return rect; }
public override void NodeGUI() { GUILayout.BeginHorizontal(); #if UNITY_EDITOR if (GUILayout.Button(new GUIContent("Load", "Loads the group from an extern Canvas Asset File."))) { string path = UnityEditor.EditorUtility.OpenFilePanel("Load Node Canvas", NodeEditor.editorPath + "Saves/", "asset"); if (!path.Contains(Application.dataPath)) { // TODO: Generic Notification //if (path != String.Empty) //ShowNotification (new GUIContent ("You should select an asset inside your project folder!")); return; } path = path.Replace(Application.dataPath, "Assets"); nodeGroupCanvas = NodeEditor.LoadNodeCanvas(path); editorState = NodeEditor.LoadEditorStates(path) [0]; editorState.drawing = edit; if (nodeGroupCanvas != null) { // Set the name string[] folders = path.Split(new char[] { '/' }, StringSplitOptions.None); string canvasName = folders [folders.Length - 1]; if (canvasName.EndsWith(".asset")) { canvasName = canvasName.Remove(canvasName.Length - 6); } name = canvasName; } else { name = "Node Group"; } //AdoptInputsOutputs (); } if (GUILayout.Button(new GUIContent("Save", "Saves the group as a new Canvas Asset File"))) { NodeEditor.SaveNodeCanvas(nodeGroupCanvas, UnityEditor.EditorUtility.SaveFilePanelInProject("Save Group Node Canvas", "Group Canvas", "asset", "Saving to a file is only needed once.", NodeEditor.editorPath + "Saves/")); } #endif if (GUILayout.Button(new GUIContent("New Group Canvas", "Creates a new Canvas (remember to save the previous one to a referenced Canvas Asset File at least once before! Else it'll be lost!)"))) { nodeGroupCanvas = CreateInstance <NodeCanvas> (); editorState = CreateInstance <NodeEditorState> (); editorState.drawing = edit; editorState.name = "GroupNode_EditorState"; } GUILayout.EndHorizontal(); foreach (NodeInput input in Inputs) { input.DisplayLayout(); } foreach (NodeOutput output in Outputs) { output.DisplayLayout(); } if (!edit && nodeGroupCanvas != null) { if (GUILayout.Button("Edit Node Canvas")) { rect = openedRect; edit = true; editorState.canvasRect = GUILayoutUtility.GetRect(canvasSize.x, canvasSize.y, GUIStyle.none); editorState.drawing = true; } } else if (nodeGroupCanvas != null) { if (GUILayout.Button("Stop editing Node Canvas")) { nodeRect.position = openedRect.position + new Vector2(canvasSize.x / 2 - nodeRect.width / 2, 0); rect = nodeRect; edit = false; editorState.drawing = false; } editorState.canvasRect = GUILayoutUtility.GetRect(canvasSize.x - 200, canvasSize.y, new GUILayoutOption[] { GUILayout.ExpandWidth(false) }); NodeEditor.curEditorState.ignoreInput.Add(NodeEditor.GUIToScreenRect(editorState.canvasRect)); NodeEditor.DrawSubCanvas(nodeGroupCanvas, editorState); GUILayout.BeginArea(new Rect(canvasSize.x - 200 + 2, editorState.canvasRect.y + 42, 200, canvasSize.y), GUI.skin.box); GUILayout.Label(new GUIContent("Node Editor (" + nodeGroupCanvas.name + ")", "The currently opened canvas in the Node Editor")); GUILayout.EndArea(); // Node is drawn by parent nodeCanvas, usually the mainNodeCanvas, because the zoom feature requires it to be drawn outside of any GUI group } }
/// <summary> /// Transforms screen position pos (like mouse pos) to a point in specified GUI space /// </summary> /// public static Vector2 ScreenToGUIPos(NodeEditorState editorState, Vector2 pos) { return Vector2.Scale (pos - editorState.zoomPos - editorState.canvasRect.position, new Vector2 (editorState.zoom, editorState.zoom)); }
protected internal override void NodeGUI() { GUILayout.BeginHorizontal(); #if UNITY_EDITOR if (GUILayout.Button(new GUIContent("Load", "Loads the group from an extern Canvas Asset File."))) { string path = UnityEditor.EditorUtility.OpenFilePanel("Load Node Canvas", NodeEditor.editorPath + "Saves/", "asset"); if (!path.Contains(Application.dataPath)) { // TODO: Generic Notification //if (path != String.Empty) //ShowNotification (new GUIContent ("You should select an asset inside your project folder!")); return; } path = path.Replace(Application.dataPath, "Assets"); LoadNodeCanvas(path); //AdoptInputsOutputs (); } if (GUILayout.Button(new GUIContent("Save", "Saves the group as a new Canvas Asset File"))) { NodeEditorSaveManager.SaveNodeCanvas(UnityEditor.EditorUtility.SaveFilePanelInProject("Save Group Node Canvas", "Group Canvas", "asset", "", NodeEditor.editorPath + "Saves/"), nodeGroupCanvas); } #endif if (GUILayout.Button(new GUIContent("New Group Canvas", "Creates a new Canvas"))) { nodeGroupCanvas = CreateInstance <NodeCanvas> (); editorState = CreateInstance <NodeEditorState> (); editorState.drawing = edit; editorState.name = "GroupNode_EditorState"; Node node = NodeTypes.getDefaultNode("exampleNode"); if (node != null) { NodeCanvas prevNodeCanvas = NodeEditor.curNodeCanvas; NodeEditor.curNodeCanvas = nodeGroupCanvas; node = node.Create(Vector2.zero); node.InitBase(); NodeEditor.curNodeCanvas = prevNodeCanvas; } } GUILayout.EndHorizontal(); if (nodeGroupCanvas != null) { foreach (NodeInput input in Inputs) { input.DisplayLayout(); } foreach (NodeOutput output in Outputs) { output.DisplayLayout(); } if (!edit) { if (GUILayout.Button("Edit Node Canvas")) { rect = openedRect; edit = true; editorState.canvasRect = GUILayoutUtility.GetRect(canvasSize.x, canvasSize.y, GUIStyle.none); editorState.drawing = true; } } else { if (GUILayout.Button("Stop editing Node Canvas")) { nodeRect.position = openedRect.position + new Vector2(canvasSize.x / 2 - nodeRect.width / 2, 0); rect = nodeRect; edit = false; editorState.drawing = false; } Rect canvasRect = GUILayoutUtility.GetRect(canvasSize.x, canvasSize.y, new GUILayoutOption[] { GUILayout.ExpandWidth(false) }); if (Event.current.type != EventType.Layout) { editorState.canvasRect = canvasRect; Rect canvasControlRect = editorState.canvasRect; canvasControlRect.position += rect.position + contentOffset; NodeEditor.curEditorState.ignoreInput.Add(NodeEditorFramework.NodeEditor.CanvasGUIToScreenRect(canvasControlRect)); } NodeEditor.DrawSubCanvas(nodeGroupCanvas, editorState); GUILayout.BeginArea(new Rect(canvasSize.x + 8, 45, 200, canvasSize.y), GUI.skin.box); GUILayout.Label(new GUIContent("Node Editor (" + nodeGroupCanvas.name + ")", "The currently opened canvas in the Node Editor")); #if UNITY_EDITOR editorState.zoom = UnityEditor.EditorGUILayout.Slider(new GUIContent("Zoom", "Use the Mousewheel. Seriously."), editorState.zoom, 0.6f, 2); #endif GUILayout.EndArea(); // Node is drawn by parent nodeCanvas, usually the mainNodeCanvas, because the zoom feature requires it to be drawn outside of any GUI group } } }
/// <summary> /// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path /// </summary> public void LoadNodeCanvas(string path) { // Load the NodeCanvas NodeCanvas nodeCanvas = NodeEditor.LoadNodeCanvas (path); if (nodeCanvas == null) return; mainNodeCanvas = nodeCanvas; // Load the associated MainEditorState List<NodeEditorState> editorStates = NodeEditor.LoadEditorStates (path); mainEditorState = editorStates.Find (x => x.name == "MainEditorState"); if (mainEditorState == null) mainEditorState = CreateInstance<NodeEditorState> (); // Set some editor properties string[] folders = path.Split (new char[] {'/'}, StringSplitOptions.None); openedCanvas = folders [folders.Length-1]; openedCanvasPath = path; NodeEditor.RecalculateAll (mainNodeCanvas); Repaint (); }
public void LoadNodeCanvas (string path) { NodeGroupCanvas = NodeEditor.LoadNodeCanvas (path); if (NodeGroupCanvas != null) { List<NodeEditorState> editorStates = NodeEditor.LoadEditorStates (path); EditorState = editorStates.Count == 0? CreateInstance<NodeEditorState> () : editorStates[0]; EditorState.Canvas = NodeGroupCanvas; EditorState.ParentEditor = NodeEditor.CurEditorState; EditorState.Drawing = Edit; EditorState.name = "GroupNode_EditorState"; string[] folders = path.Split (new char[] {'/'}, StringSplitOptions.None); string canvasName = folders [folders.Length-1]; if (canvasName.EndsWith (".asset")) canvasName = canvasName.Remove (canvasName.Length-6); name = canvasName; } else name = "Node Group"; }
/// <summary> /// Converts the NodeCanvas to a simplified CanvasData /// </summary> internal static CanvasData ConvertToCanvasData(NodeCanvas canvas) { if (canvas == null) { return(null); } // Validate canvas and create canvas data for it canvas.Validate(); CanvasData canvasData = new CanvasData(canvas); // Store Lookup-Table for all ports Dictionary <ConnectionPort, PortData> portDatas = new Dictionary <ConnectionPort, PortData>(); foreach (Node node in canvas.nodes) { // Create node data NodeData nodeData = new NodeData(node); canvasData.nodes.Add(nodeData.nodeID, nodeData); foreach (ConnectionPortDeclaration portDecl in ConnectionPortManager.GetPortDeclarationEnumerator(node)) { // Fetch all static connection port declarations and record them ConnectionPort port = (ConnectionPort)portDecl.portField.GetValue(node); PortData portData = new PortData(nodeData, port, portDecl.portField.Name); nodeData.connectionPorts.Add(portData); portDatas.Add(port, portData); } foreach (ConnectionPort port in node.dynamicConnectionPorts) { // Fetch all dynamic connection ports and record them PortData portData = new PortData(nodeData, port); nodeData.connectionPorts.Add(portData); portDatas.Add(port, portData); } // Fetch all serialized node variables specific to each node's implementation FieldInfo[] serializedFields = ReflectionUtility.getSerializedFields(node.GetType(), typeof(Node)); foreach (FieldInfo field in serializedFields) { // Create variable data and enter the if (field.FieldType.IsSubclassOf(typeof(ConnectionPort))) { continue; } VariableData varData = new VariableData(field); nodeData.variables.Add(varData); object varValue = field.GetValue(node); if (field.FieldType.IsValueType) // Store value of the object { varData.value = varValue; } else // Store reference to the object { varData.refObject = canvasData.ReferenceObject(varValue); } } } foreach (PortData portData in portDatas.Values) { // Record the connections of this port foreach (ConnectionPort conPort in portData.port.connections) { PortData conPortData; // Get portData associated with the connection port if (portDatas.TryGetValue(conPort, out conPortData)) { canvasData.RecordConnection(portData, conPortData); } } } foreach (NodeGroup group in canvas.groups) { // Record all groups canvasData.groups.Add(new GroupData(group)); } canvasData.editorStates = new EditorStateData[canvas.editorStates.Length]; for (int i = 0; i < canvas.editorStates.Length; i++) { // Record all editorStates NodeEditorState state = canvas.editorStates[i]; NodeData selected = state.selectedNode == null ? null : canvasData.FindNode(state.selectedNode); canvasData.editorStates[i] = new EditorStateData(selected, state.panOffset, state.zoom); } return(canvasData); }
public void ChangeState( NodeEditorState state ) { this.state = state; }