/// <summary> /// Removes the connection of this port to the specified port if existant /// </summary> public void RemoveConnection(ConnectionPort port, bool silent = false) { #if UNITY_EDITOR if (silent == false && port != null) { // Undo record // Important: Copy variables used within anonymous functions within same level (this if block) for correct serialization! ConnectionPort port1 = this, port2 = port; UndoPro.UndoProManager.RecordOperation( () => NodeEditorUndoActions.DeleteConnection(port1, port2), () => NodeEditorUndoActions.CreateConnection(port1, port2), "Delete Connection"); } #endif if (port == null) { Debug.LogWarning("Cannot delete null port!"); //connections.RemoveAll (p => p != null); return; } if (!silent) { NodeEditorCallbacks.IssueOnRemoveConnection(this, port); } port.connections.Remove(this); connections.Remove(port); if (!silent) { body.canvas.OnNodeChange(body); } }
[EventHandlerAttribute(EventType.MouseDown, -2)] // Absolute second to call! private static void HandleSelecting(NodeEditorInputInfo inputInfo) { if (inputInfo.inputEvent.button == 0 && inputInfo.editorState.focusedNode != inputInfo.editorState.selectedNode) { // Select focussed Node unfocusControlsForState = inputInfo.editorState; inputInfo.editorState.selectedNode = inputInfo.editorState.focusedNode; #if UNITY_EDITOR NodeEditorState state = inputInfo.editorState; Node prevSelection = state.selectedNode, newSelection = state.focusedNode; UndoPro.UndoProManager.RecordOperation( () => NodeEditorUndoActions.SetNodeSelection(state, newSelection), () => NodeEditorUndoActions.SetNodeSelection(state, prevSelection), "Node Selection", false, true); #endif } #if UNITY_EDITOR if (inputInfo.editorState.selectedNode != null) { UnityEditor.Selection.activeObject = inputInfo.editorState.selectedNode; } else if (UnityEditor.Selection.activeObject is Node) { UnityEditor.Selection.activeObject = inputInfo.editorState.canvas; } #endif }
[EventHandlerAttribute(EventType.MouseDown, -2)] // Absolute second to call! private static void HandleSelecting(NodeEditorInputInfo inputInfo) { if (inputInfo.inputEvent.button == 0 && inputInfo.editorState.focusedNode != inputInfo.editorState.selectedNode) { // Select focussed Node inputInfo.editorState.selectedNode = inputInfo.editorState.focusedNode; #if UNITY_EDITOR NodeEditorState state = inputInfo.editorState; Node prevSelection = state.selectedNode, newSelection = state.focusedNode; UndoPro.UndoProManager.RecordOperation( () => NodeEditorUndoActions.SetNodeSelection(state, newSelection), () => NodeEditorUndoActions.SetNodeSelection(state, prevSelection), "Node Selection", false, true); #endif // Make sure previous controls get unfocussed later, but except if control is in newly selected node unfocusControlsForState = inputInfo.editorState; unfocusControlsHot = GUIUtility.hotControl; unfocusControlsKeyboard = GUIUtility.keyboardControl; } #if UNITY_EDITOR if (inputInfo.editorState.selectedNode != null) { UnityEditor.Selection.activeObject = inputInfo.editorState.selectedNode; } else if (UnityEditor.Selection.activeObject is Node) { UnityEditor.Selection.activeObject = inputInfo.editorState.canvas; } #endif }
private static void HandleNodeDraggingEnd(NodeEditorInputInfo inputInfo) { if (inputInfo.editorState.dragUserID == "node") { Vector2 dragStart = inputInfo.editorState.dragObjectStart; Vector2 dragEnd = inputInfo.editorState.EndDrag("node"); if (inputInfo.editorState.dragNode && inputInfo.editorState.selectedNode) { if ((dragStart - dragEnd).magnitude > 10) { inputInfo.editorState.selectedNode.position = dragEnd; #if UNITY_EDITOR // Important: Copy variables used within anonymous functions within same level (this if block) for correct serialization! float prevX = dragStart.x, prevY = dragStart.y, newX = dragEnd.x, newY = dragEnd.y; Node draggedNode = inputInfo.editorState.selectedNode; UndoPro.UndoProManager.RecordOperation( () => NodeEditorUndoActions.SetNodePosition(draggedNode, new Vector2(newX, newY)), () => NodeEditorUndoActions.SetNodePosition(draggedNode, new Vector2(prevX, prevY)), "Node Drag", true, false); #endif NodeEditorCallbacks.IssueOnMoveNode(inputInfo.editorState.selectedNode); } else { inputInfo.editorState.selectedNode.position = dragStart; } } } inputInfo.editorState.dragNode = false; }
/// <summary> /// Deletes this Node from it's host canvas and the save file /// </summary> public void Delete(bool silent = false) { if (!canvas.nodes.Contains(this)) { throw new UnityException("The Node " + name + " does not exist on the Canvas " + canvas.name + "!"); } if (!silent) { NodeEditorCallbacks.IssueOnDeleteNode(this); } #if UNITY_EDITOR if (!silent) { List <ConnectionPort> connectedPorts = new List <ConnectionPort>(); foreach (ConnectionPort port in connectionPorts) { // 'Encode' connected ports in one list (double level cannot be serialized) foreach (ConnectionPort conn in port.connections) { connectedPorts.Add(conn); } connectedPorts.Add(null); } Node deleteNode = this; UndoPro.UndoProManager.RecordOperation( () => NodeEditorUndoActions.RemoveNode(deleteNode), () => NodeEditorUndoActions.ReinstateNode(deleteNode, connectedPorts), "Delete Node"); // Make sure the deleted node is in the memory dump NodeEditorUndoActions.CompleteSOMemoryDump(canvas); } #endif canvas.nodes.Remove(this); for (int i = 0; i < connectionPorts.Count; i++) { connectionPorts[i].ClearConnections(true); } if (!silent) { canvas.Validate(); } }
/// <summary> /// Saves the current canvas to the cache /// </summary> public void SaveCache(bool crashSafe = true) { #if CACHE if (!useCache) { return; } if (!nodeCanvas || nodeCanvas.GetType() == typeof(NodeCanvas)) { return; } UnityEditor.EditorUtility.SetDirty(nodeCanvas); if (editorState != null) { UnityEditor.EditorUtility.SetDirty(editorState); } lastCacheTime = UnityEditor.EditorApplication.timeSinceStartup; nodeCanvas.editorStates = new NodeEditorState[] { editorState }; if (nodeCanvas.livesInScene || nodeCanvas.allowSceneSaveOnly) { NodeEditorSaveManager.SaveSceneNodeCanvas("lastSession", ref nodeCanvas, cacheWorkingCopy); } else if (crashSafe) { NodeEditorSaveManager.SaveNodeCanvas(lastSessionPath, ref nodeCanvas, cacheWorkingCopy, true); } if (cacheMemorySODump) { // Functionality for asset saves only if (nodeCanvas.livesInScene || nodeCanvas.allowSceneSaveOnly) { // Delete for scene save so that next cache load, correct lastSession is used UnityEditor.AssetDatabase.DeleteAsset(SOMemoryDumpPath); } else { // Dump all SOs used in this session (even if deleted) in this file to keep them alive for undo NodeEditorUndoActions.CompleteSOMemoryDump(nodeCanvas); NodeEditorSaveManager.ScriptableObjectReferenceDump(nodeCanvas.SOMemoryDump, SOMemoryDumpPath, false); } } #endif }
/// <summary> /// Applies a connection between between this port and the specified port. /// 'CanApplyConnection' has to be checked before to avoid interferences! /// </summary> public void ApplyConnection(ConnectionPort port, bool silent = false) { if (port == null) { return; } if (maxConnectionCount == ConnectionCount.Single && connections.Count > 0) { // Respect maximum connection count on this port RemoveConnection(connections[0], silent); connections.Clear(); } connections.Add(port); if (port.maxConnectionCount == ConnectionCount.Single && port.connections.Count > 0) { // Respect maximum connection count on the other port port.RemoveConnection(port.connections[0], silent); port.connections.Clear(); } port.connections.Add(this); #if UNITY_EDITOR if (!silent) { // Create Undo record // Important: Copy variables used within anonymous functions within same level (this if block) for correct serialization! ConnectionPort port1 = this, port2 = port; UndoPro.UndoProManager.RecordOperation( () => NodeEditorUndoActions.CreateConnection(port1, port2), () => NodeEditorUndoActions.DeleteConnection(port1, port2), "Create Connection"); } #endif if (!silent) { // Callbacks port.body.OnAddConnection(port, this); body.OnAddConnection(this, port); NodeEditorCallbacks.IssueOnAddConnection(this, port); body.canvas.OnNodeChange(direction == Direction.In? port.body : body); } }
/// <summary> /// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path /// </summary> public void LoadNodeCanvas(string path) { // Try to load the NodeCanvas if (!File.Exists(path) || (nodeCanvas = NodeEditorSaveManager.LoadNodeCanvas(path, true)) == null) { NewNodeCanvas(); return; } editorState = NodeEditorSaveManager.ExtractEditorState(nodeCanvas, MainEditorStateIdentifier); openedCanvasPath = path; nodeCanvas.Validate(); RecreateCache(); UpdateCanvasInfo(); nodeCanvas.TraverseAll(); NodeEditor.RepaintClients(); #if UNITY_EDITOR UnityEditor.AssetDatabase.DeleteAsset(SOMemoryDumpPath); NodeEditorUndoActions.CompleteSOMemoryDump(nodeCanvas); #endif }
/// <summary> /// Creates a node of the specified ID at pos on the specified canvas, optionally auto-connecting the specified output to a matching input /// silent disables any events, init specifies whether OnCreate should be called /// </summary> public static Node Create(string nodeID, Vector2 pos, NodeCanvas hostCanvas, ConnectionPort connectingPort = null, bool silent = false, bool init = true) { if (string.IsNullOrEmpty(nodeID) || hostCanvas == null) { throw new ArgumentException(); } if (!NodeCanvasManager.CheckCanvasCompability(nodeID, hostCanvas.GetType())) { throw new UnityException("Cannot create Node with ID '" + nodeID + "' as it is not compatible with the current canavs type (" + hostCanvas.GetType().ToString() + ")!"); } if (!hostCanvas.CanAddNode(nodeID)) { throw new UnityException("Cannot create Node with ID '" + nodeID + "' on the current canvas of type (" + hostCanvas.GetType().ToString() + ")!"); } // Create node from data NodeTypeData data = NodeTypes.getNodeData(nodeID); Node node = (Node)CreateInstance(data.type); if (node == null) { return(null); } // Init node state node.canvas = hostCanvas; node.name = node.Title; node.autoSize = node.DefaultSize; node.position = pos; ConnectionPortManager.UpdateConnectionPorts(node); if (init) { node.OnCreate(); } if (connectingPort != null) { // Handle auto-connection and link the output to the first compatible input for (int i = 0; i < node.connectionPorts.Count; i++) { if (node.connectionPorts[i].TryApplyConnection(connectingPort, true)) { break; } } } // Add node to host canvas hostCanvas.nodes.Add(node); if (!silent) { // Callbacks hostCanvas.OnNodeChange(connectingPort != null ? connectingPort.body : node); NodeEditorCallbacks.IssueOnAddNode(node); hostCanvas.Validate(); NodeEditor.RepaintClients(); } #if UNITY_EDITOR if (!silent) { List <ConnectionPort> connectedPorts = new List <ConnectionPort>(); foreach (ConnectionPort port in node.connectionPorts) { // 'Encode' connected ports in one list (double level cannot be serialized) foreach (ConnectionPort conn in port.connections) { connectedPorts.Add(conn); } connectedPorts.Add(null); } Node createdNode = node; UndoPro.UndoProManager.RecordOperation( () => NodeEditorUndoActions.ReinstateNode(createdNode, connectedPorts), () => NodeEditorUndoActions.RemoveNode(createdNode), "Create Node"); // Make sure the new node is in the memory dump NodeEditorUndoActions.CompleteSOMemoryDump(hostCanvas); } #endif return(node); }