/// <summary> /// Transforms the Rect in GUI space into Screen space /// </summary> public static Rect CanvasGUIToScreenRect(NodeEditorState editorState, Rect rect) { rect.position += editorState.zoomPos; rect = GUIScaleUtility.ScaleRect (rect, editorState.zoomPos, editorState.parentEditor != null? new Vector2 (1/(editorState.parentEditor.zoom*editorState.zoom), 1/(editorState.parentEditor.zoom*editorState.zoom)) : new Vector2 (1/editorState.zoom, 1/editorState.zoom)); rect.position += editorState.canvasRect.position; return rect; }
public static void IssueOnLoadEditorState (NodeEditorState editorState) { if (OnLoadEditorState != null) OnLoadEditorState.Invoke (editorState); for (int cnt = 0; cnt < receiverCount; cnt++) { if (callbackReceiver [cnt] == null) callbackReceiver.RemoveAt (cnt--); else callbackReceiver [cnt].OnLoadEditorState (editorState) ; } }
/// <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; for (int nodeCnt = nodeCanvas.nodes.Count-1; nodeCnt >= 0; nodeCnt--) { // Check from top to bottom because of the render order Node node = nodeCanvas.nodes [nodeCnt]; if (CanvasGUIToScreenRect (node.rect).Contains (pos)) // Node Body return node; foreach (NodeKnob knob in node.nodeKnobs) { // Any edge control if (knob.GetScreenKnob ().Contains (pos)) return node; } } return null; }
/// <summary> /// Draws the Node Canvas on the screen in the rect specified by editorState /// </summary> public static void DrawCanvas (NodeCanvas nodeCanvas, NodeEditorState editorState) { if (!editorState.drawing) return; checkInit (); NodeEditorGUI.StartNodeGUI (); OverlayGUI.StartOverlayGUI (); DrawSubCanvas (nodeCanvas, editorState); OverlayGUI.EndOverlayGUI (); NodeEditorGUI.EndNodeGUI (); }
/// <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: var createPos = ScreenToGUIPos (mousePos); if (cbObj.nodeOutput != null && (curEditorState.connectMousePos - mousePos).sqrMagnitude < 50) createPos = new Vector2(cbObj.nodeOutput.body.rect.xMax+50, cbObj.nodeOutput.body.rect.yMin); foreach (Node node in NodeTypes.nodes.Keys) { if (node.GetID == cbObj.message) { var newNode = node.Create (createPos); newNode.InitBase (); if (cbObj.nodeOutput != null) { // If nodeOutput is defined, link it to the first input of the same type foreach (var input in newNode.Inputs) { 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; } }
/// <summary> /// Transforms screen space elements in the specified editor into canvas space (Level of Nodes, ...) /// </summary> public static Vector2 ScreenToCanvasSpace(NodeEditorState editorState, Vector2 screenPos) { return((screenPos - editorState.canvasRect.position - editorState.zoomPos) * editorState.zoom - editorState.panOffset); }
/// <summary> /// Draws the Node Canvas on the screen in the rect specified by editorState without one-time wrappers like GUISkin and OverlayGUI. Made for nested Canvases (WIP) /// </summary> private static void DrawSubCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState) { if (!editorState.drawing) { return; } // Store and restore later on in case of this being a nested Canvas NodeCanvas prevNodeCanvas = curNodeCanvas; NodeEditorState prevEditorState = curEditorState; curNodeCanvas = nodeCanvas; curEditorState = editorState; if (Event.current.type == EventType.Repaint) { // Draw Background when Repainting // Size in pixels the inividual background tiles will have on screen float width = curEditorState.zoom / NodeEditorGUI.Background.width; float height = curEditorState.zoom / NodeEditorGUI.Background.height; // Offset of the grid relative to the GUI origin Vector2 offset = curEditorState.zoomPos + curEditorState.panOffset / curEditorState.zoom; // Rect in UV space that defines how to tile the background texture Rect uvDrawRect = new Rect(-offset.x * width, (offset.y - curEditorState.canvasRect.height) * height, curEditorState.canvasRect.width * width, curEditorState.canvasRect.height * height); GUI.DrawTextureWithTexCoords(curEditorState.canvasRect, NodeEditorGUI.Background, uvDrawRect); } // Handle input events NodeEditorInputSystem.HandleInputEvents(curEditorState); if (Event.current.type != EventType.Layout) { curEditorState.ignoreInput = new List <Rect> (); } // We're using a custom scale method, as default one is messing up clipping rect Rect canvasRect = curEditorState.canvasRect; curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale(ref canvasRect, curEditorState.zoomPos, curEditorState.zoom, false); // ---- BEGIN SCALE ---- // Some features which require zoomed drawing: if (curEditorState.navigate) { // Draw a curve to the origin/active node for orientation purposes Vector2 startPos = (curEditorState.selectedNode != null? curEditorState.selectedNode.rect.center : curEditorState.panOffset) + curEditorState.zoomPanAdjust; Vector2 endPos = Event.current.mousePosition; RTEditorGUI.DrawLine(startPos, endPos, Color.green, null, 3); RepaintClients(); } if (curEditorState.connectOutput != null) { // Draw the currently drawn connection NodeOutput output = curEditorState.connectOutput; Vector2 startPos = output.GetGUIKnob().center; Vector2 startDir = output.GetDirection(); Vector2 endPos = Event.current.mousePosition; // There is no specific direction of the end knob so we pick the best according to the relative position Vector2 endDir = NodeEditorGUI.GetSecondConnectionVector(startPos, endPos, startDir); NodeEditorGUI.DrawConnection(startPos, startDir, endPos, endDir, output.typeData.Color); RepaintClients(); } // Push the active node to the top of the draw order. if (Event.current.type == EventType.Layout && curEditorState.selectedNode != null) { curNodeCanvas.nodes.Remove(curEditorState.selectedNode); curNodeCanvas.nodes.Add(curEditorState.selectedNode); } // Draw the transitions and connections. Has to be drawn before nodes as transitions originate from node centers for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { curNodeCanvas.nodes [nodeCnt].DrawConnections(); } // Draw the nodes for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { Node node = curNodeCanvas.nodes [nodeCnt]; node.DrawNode(); if (Event.current.type == EventType.Repaint) { node.DrawKnobs(); } } // ---- END SCALE ---- // End scaling group GUIScaleUtility.EndScale(); // Handle input events with less priority than node GUI controls NodeEditorInputSystem.HandleLateInputEvents(curEditorState); curNodeCanvas = prevNodeCanvas; curEditorState = prevEditorState; }
/// <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))); }
/// <summary> /// Transforms screen space elements in the specified editor into canvas space (Level of Nodes, ...) /// </summary> public static Vector2 CanvasSpaceToScreen(NodeEditorState editorState, Vector2 canvasPos) { return((canvasPos + editorState.canvasRect.position + editorState.zoomPos) / editorState.zoom + editorState.panOffset); //(screenPos - editorState.canvasRect.position - editorState.zoomPos) * editorState.zoom - editorState.panOffset; }
/// <summary> /// Evaluates context callbacks previously registered /// </summary> public static void ContextCallback(object obj) { NodeEditorMenuCallback callback = obj as NodeEditorMenuCallback; if (callback == null) { throw new UnityException("Callback Object passed by context is not of type NodeEditorMenuCallback!"); } curNodeCanvas = callback.canvas; curEditorState = callback.editor; switch (callback.message) { case "deleteNode": // Delete request if (curEditorState.focusedNode != null) { curEditorState.focusedNode.Delete(); } break; case "duplicateNode": // Duplicate request if (curEditorState.focusedNode != null) { ContextCallback(new NodeEditorMenuCallback(curEditorState.focusedNode.GetID, curNodeCanvas, curEditorState)); Node duplicatedNode = curNodeCanvas.nodes [curNodeCanvas.nodes.Count - 1]; curEditorState.focusedNode = duplicatedNode; curEditorState.dragNode = true; curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.panWindow = false; } break; case "startTransition": // Starting a new transition if (curEditorState.focusedNode != null) { curEditorState.makeTransition = curEditorState.focusedNode; curEditorState.connectOutput = null; } curEditorState.dragNode = false; curEditorState.panWindow = false; break; default: // Node creation request Node node = Node.Create(callback.message, ScreenToGUIPos(callback.contextClickPos)); // Handle auto-connection if (curEditorState.connectOutput != null) { // If nodeOutput is defined, link it to the first input of the same type foreach (NodeInput input in node.Inputs) { if (input.CanApplyConnection(curEditorState.connectOutput)) { // If it can connect (type is equals, it does not cause recursion, ...) input.ApplyConnection(curEditorState.connectOutput); break; } } } curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.dragNode = false; curEditorState.panWindow = false; break; } RepaintClients(); }
/// <summary> /// Draws the Node Canvas on the screen in the rect specified by editorState without one-time wrappers like GUISkin and OverlayGUI. Made for nested Canvases (WIP) /// </summary> public static void DrawSubCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState) { if (!editorState.drawing) { return; } // Store and restore later on in case of this being a nested Canvas NodeCanvas prevNodeCanvas = curNodeCanvas; NodeEditorState prevEditorState = curEditorState; curNodeCanvas = nodeCanvas; curEditorState = editorState; if (Event.current.type == EventType.Repaint) { // Draw Background when Repainting GUI.BeginClip(curEditorState.canvasRect); float width = NodeEditorGUI.Background.width / curEditorState.zoom; float height = NodeEditorGUI.Background.height / curEditorState.zoom; Vector2 offset = curEditorState.zoomPos + curEditorState.panOffset / curEditorState.zoom; offset = new Vector2(offset.x % width - width, offset.y % 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++) { GUI.DrawTexture(new Rect(offset.x + x * width, offset.y + y * height, width, height), NodeEditorGUI.Background); } } GUI.EndClip(); } // Check the inputs InputEvents(); if (Event.current.type != EventType.Layout) { curEditorState.ignoreInput = new List <Rect> (); } // We're using a custom scale method, as default one is messing up clipping rect Rect canvasRect = curEditorState.canvasRect; curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale(ref canvasRect, curEditorState.zoomPos, curEditorState.zoom, false); //GUILayout.Label ("Scaling is Great!"); -> TODO: Test by changing the last bool parameter // ---- BEGIN SCALE ---- // Some features which require drawing (zoomed) if (curEditorState.navigate) { // Draw a curve to the origin/active node for orientation purposes RTEditorGUI.DrawLine((curEditorState.selectedNode != null? curEditorState.selectedNode.rect.center : curEditorState.panOffset) + curEditorState.zoomPanAdjust, ScreenToGUIPos(mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.black, null, 3); RepaintClients(); } if (curEditorState.connectOutput != null) { // Draw the currently drawn connection NodeOutput output = curEditorState.connectOutput; Vector2 startPos = output.GetGUIKnob().center; Vector2 endPos = ScreenToGUIPos(mousePos) + curEditorState.zoomPos * curEditorState.zoom; Vector2 endDir = output.GetDirection(); NodeEditorGUI.DrawConnection(startPos, endDir, endPos, NodeEditorGUI.GetSecondConnectionVector(startPos, endPos, endDir), ConnectionTypes.GetTypeData(output.type, true).Color); RepaintClients(); } if (curEditorState.makeTransition != null) { // Draw the currently made transition RTEditorGUI.DrawLine(curEditorState.makeTransition.rect.center + curEditorState.zoomPanAdjust, ScreenToGUIPos(mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.grey, null, 3); RepaintClients(); } // Push the active node at the bottom of the draw order. if (Event.current.type == EventType.Layout && curEditorState.selectedNode != null) { curNodeCanvas.nodes.Remove(curEditorState.selectedNode); curNodeCanvas.nodes.Add(curEditorState.selectedNode); } // Draw the transitions and connections. Has to be drawn before nodes as transitions originate from node centers foreach (Node node in curNodeCanvas.nodes) { node.DrawConnections(); } // Draw the nodes foreach (Node node in curNodeCanvas.nodes) { node.DrawNode(); if (Event.current.type == EventType.Repaint) { node.DrawKnobs(); } } // ---- END SCALE ---- // End scaling group GUIScaleUtility.EndScale(); // Check events with less priority than node GUI controls LateEvents(); curNodeCanvas = prevNodeCanvas; curEditorState = prevEditorState; }
/// <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) { DrawCanvas (nodeCanvas, editorState, new Rect ()); }
private static void DrawSubCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState) { if (editorState.drawing) { NodeCanvas nodeCanvas2 = curNodeCanvas; NodeEditorState nodeEditorState = curEditorState; curNodeCanvas = nodeCanvas; curEditorState = editorState; if (Event.current.type == EventType.Repaint) { float num = curEditorState.zoom / (float)NodeEditorGUI.Background.width; float num2 = curEditorState.zoom / (float)NodeEditorGUI.Background.height; Vector2 vector = curEditorState.zoomPos + curEditorState.panOffset / curEditorState.zoom; GUI.DrawTextureWithTexCoords(texCoords: new Rect((0f - vector.x) * num, (vector.y - curEditorState.canvasRect.height) * num2, curEditorState.canvasRect.width * num, curEditorState.canvasRect.height * num2), position: curEditorState.canvasRect, image: NodeEditorGUI.Background); } NodeEditorInputSystem.HandleInputEvents(curEditorState); if (Event.current.type != EventType.Layout) { curEditorState.ignoreInput = new List <Rect>(); } Rect rect = curEditorState.canvasRect; curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale(ref rect, curEditorState.zoomPos, curEditorState.zoom, false); if (curEditorState.navigate) { Vector2 startPos = ((!((UnityEngine.Object)curEditorState.selectedNode != (UnityEngine.Object)null)) ? curEditorState.panOffset : curEditorState.selectedNode.rect.center) + curEditorState.zoomPanAdjust; Vector2 mousePosition = Event.current.mousePosition; RTEditorGUI.DrawLine(startPos, mousePosition, Color.green, null, 3f); RepaintClients(); } if ((UnityEngine.Object)curEditorState.connectOutput != (UnityEngine.Object)null) { NodeOutput connectOutput = curEditorState.connectOutput; Vector2 center = connectOutput.GetGUIKnob().center; Vector2 direction = connectOutput.GetDirection(); Vector2 mousePosition2 = Event.current.mousePosition; Vector2 secondConnectionVector = NodeEditorGUI.GetSecondConnectionVector(center, mousePosition2, direction); NodeEditorGUI.DrawConnection(center, direction, mousePosition2, secondConnectionVector, connectOutput.typeData.Color); RepaintClients(); } if (Event.current.type == EventType.Layout && (UnityEngine.Object)curEditorState.selectedNode != (UnityEngine.Object)null) { curNodeCanvas.nodes.Remove(curEditorState.selectedNode); curNodeCanvas.nodes.Add(curEditorState.selectedNode); } for (int i = 0; i < curNodeCanvas.nodes.Count; i++) { curNodeCanvas.nodes[i].DrawConnections(); } for (int j = 0; j < curNodeCanvas.nodes.Count; j++) { Node node = curNodeCanvas.nodes[j]; node.DrawNode(); if (Event.current.type == EventType.Repaint) { node.DrawKnobs(); } } GUIScaleUtility.EndScale(); NodeEditorInputSystem.HandleLateInputEvents(curEditorState); curNodeCanvas = nodeCanvas2; curEditorState = nodeEditorState; } }
/// <summary> /// Creates and opens a new empty node canvas /// </summary> public void NewNodeCanvas() { // Else it will be stuck forever NodeEditor.StopTransitioning (mainNodeCanvas); // New NodeCanvas mainNodeCanvas = CreateInstance<NodeCanvas> (); mainNodeCanvas.name = "New Canvas"; // New NodeEditorState mainEditorState = CreateInstance<NodeEditorState> (); mainEditorState.canvas = mainNodeCanvas; mainEditorState.name = "MainEditorState"; openedCanvasPath = ""; SaveCache (); }
/// <summary> /// Evaluates context callbacks previously registered /// </summary> public static void ContextCallback (object obj) { NodeEditorMenuCallback callback = obj as NodeEditorMenuCallback; if (callback == null) throw new UnityException ("Callback Object passed by context is not of type NodeEditorMenuCallback!"); curNodeCanvas = callback.canvas; curEditorState = callback.editor; switch (callback.message) { case "deleteNode": // Delete request if (curEditorState.focusedNode != null) curEditorState.focusedNode.Delete (); break; case "duplicateNode": // Duplicate request if (curEditorState.focusedNode != null) { ContextCallback (new NodeEditorMenuCallback (curEditorState.focusedNode.GetID, curNodeCanvas, curEditorState)); Node duplicatedNode = curNodeCanvas.nodes [curNodeCanvas.nodes.Count-1]; curEditorState.focusedNode = duplicatedNode; curEditorState.dragNode = true; curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.panWindow = false; } break; case "startTransition": // Starting a new transition if (curEditorState.focusedNode != null) { curEditorState.makeTransition = curEditorState.focusedNode; curEditorState.connectOutput = null; } curEditorState.dragNode = false; curEditorState.panWindow = false; break; default: // Node creation request Node node = Node.Create (callback.message, ScreenToGUIPos (callback.contextClickPos)); // Handle auto-connection if (curEditorState.connectOutput != null) { // If nodeOutput is defined, link it to the first input of the same type foreach (NodeInput input in node.Inputs) { if (input.CanApplyConnection (curEditorState.connectOutput)) { // If it can connect (type is equals, it does not cause recursion, ...) input.ApplyConnection (curEditorState.connectOutput); break; } } } curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.dragNode = false; curEditorState.panWindow = false; break; } RepaintClients (); }
public virtual void OnLoadEditorState (NodeEditorState editorState) {}
/// <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) { NewNodeCanvas (); 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 openedCanvasPath = path; NodeEditor.RecalculateAll (mainNodeCanvas); Repaint (); }
/// <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 (); }
/// <summary> /// Draws the Node Canvas on the screen in the rect specified by editorState without one-time wrappers like GUISkin and OverlayGUI. Made for nested Canvases (WIP) /// </summary> private static void DrawSubCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState) { if (!editorState.drawing) { return; } BeginEditingCanvas(nodeCanvas, editorState); if (curNodeCanvas == null || curEditorState == null || !curEditorState.drawing) { return; } if (Event.current.type == EventType.Repaint) { //绘制NodeEditor背景 EditorGUI.DrawRect(curEditorState.canvasRect, new Color(28 / 255f, 28 / 255f, 28 / 255f)); } // Handle input events NodeEditorInputSystem.HandleInputEvents(curEditorState); HandleMultipleSelect(); if (Event.current.type != EventType.Layout) { curEditorState.ignoreInput = new List <Rect>(); } // We're using a custom scale method, as default one is messing up clipping rect Rect canvasRect = curEditorState.canvasRect; curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale(ref canvasRect, curEditorState.zoomPos, curEditorState.zoom, NodeEditorGUI.isEditorWindow, false); // 开始绘制缩放区域 if (curEditorState.connectKnob != null) { // Draw the currently drawn connection curEditorState.connectKnob.DrawConnection(Event.current.mousePosition); RepaintClients(); } // Draw the groups below everything else for (int groupCnt = 0; groupCnt < curNodeCanvas.groups.Count; groupCnt++) { NodeGroup group = curNodeCanvas.groups[groupCnt]; if (Event.current.type == EventType.Layout) { group.isClipped = !curEditorState.canvasViewport.Overlaps(group.fullAABBRect); } if (!group.isClipped) { group.DrawGroup(); } } // Draw the transitions and connections. Has to be drawn before nodes as transitions originate from node centers for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { curNodeCanvas.nodes[nodeCnt].DrawConnections(); } // Draw the nodes for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { Node node = curNodeCanvas.nodes[nodeCnt]; if (Event.current.type == EventType.Layout) { node.isClipped = !curEditorState.canvasViewport.Overlaps(curNodeCanvas.nodes[nodeCnt].fullAABBRect); } if (node.isClipped) { continue; } node.DrawNode(); if (Event.current.type == EventType.Repaint) { node.DrawKnobs(); } } // ---- END SCALE ---- // End scaling group GUIScaleUtility.EndScale(); // Handle input events with less priority than node GUI controls NodeEditorInputSystem.HandleLateInputEvents(curEditorState); EndEditingCanvas(); }
public callbackObject(string Message, NodeCanvas nodecanvas, NodeEditorState editorState) { message = Message; canvas = nodecanvas; editor = editorState; }
public callbackObject(string Message, NodeCanvas nodecanvas, NodeEditorState editorState) { message = Message; canvas = nodecanvas; editor = editorState; }
public static void BeginEditingCanvas(NodeCanvas canvas) { NodeEditorState state = canvas.editorStates.Length >= 1? canvas.editorStates[0] : null; BeginEditingCanvas(canvas, state); }
/// <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 (curEditorState.focusedNode != null) curEditorState.focusedNode.Delete (); break; case "duplicateNode": if (curEditorState.focusedNode != null) { ContextCallback (new callbackObject (curEditorState.focusedNode.GetID, curNodeCanvas, curEditorState)); Node duplicatedNode = curNodeCanvas.nodes [curNodeCanvas.nodes.Count-1]; curEditorState.focusedNode = duplicatedNode; curEditorState.dragNode = true; curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.panWindow = false; } break; case "startTransition": if (curEditorState.focusedNode != null) { curEditorState.makeTransition = curEditorState.focusedNode; curEditorState.connectOutput = null; } curEditorState.dragNode = false; curEditorState.panWindow = false; break; default: Vector2 createPos = ScreenToGUIPos (mousePos); Node node = NodeTypes.getDefaultNode (cbObj.message); if (node == null) break; bool acceptTransitions = NodeTypes.nodes [node].transitions; node = node.Create (createPos); node.InitBase (); NodeEditorCallbacks.IssueOnAddNode (node); if (curEditorState.connectOutput != null) { // If nodeOutput is defined, link it to the first input of the same type foreach (NodeInput input in node.Inputs) { if (Node.CanApplyConnection (curEditorState.connectOutput, input)) { // If it can connect (type is equals, it does not cause recursion, ...) Node.ApplyConnection (curEditorState.connectOutput, input); break; } } } else if (acceptTransitions && curEditorState.makeTransition != null) { Node.CreateTransition (curEditorState.makeTransition, node); } curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.dragNode = false; curEditorState.panWindow = false; break; } }
public virtual void OnSaveEditorState(NodeEditorState editorState) { }
/// <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, Action repaint) { if (!editorState.drawing) return; curNodeCanvas = nodeCanvas; curEditorState = editorState; if (repaint != null) Repaint += repaint; // 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 DrawLine (curEditorState.activeNode != null? curEditorState.activeNode.rect.center + curEditorState.zoomPanAdjust : curEditorState.panOffset, ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.black, null, 3); if (Repaint != null) Repaint (); } if (curEditorState.connectOutput != null) { // Draw the currently drawn connection DrawConnection (curEditorState.connectOutput.GetGUIKnob ().center, ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom, ConnectionTypes.GetTypeData (curEditorState.connectOutput.type).col); if (Repaint != null) Repaint (); } if (curEditorState.makeTransition != null) { // Draw the currently made transition DrawLine (curEditorState.makeTransition.rect.center + curEditorState.zoomPanAdjust, ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.grey, null, 3); if (Repaint != null) Repaint (); } // Draw the Node 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 (); for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) curNodeCanvas.nodes [nodeCnt].DrawTransitions (); // 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 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, Repaint); 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> /// Draws the Node Canvas on the screen in the rect specified by editorState without one-time wrappers like GUISkin and OverlayGUI. Made for nested Canvases (WIP) /// </summary> private static void DrawSubCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState) { if (!editorState.drawing) { return; } BeginEditingCanvas(nodeCanvas, editorState); if (curNodeCanvas == null || curEditorState == null || !curEditorState.drawing) { return; } if (Event.current.type == EventType.Repaint) { // Draw Background when Repainting // Offset from origin in tile units Vector2 tileOffset = new Vector2( -(curEditorState.zoomPos.x * curEditorState.zoom + curEditorState.panOffset.x) / NodeEditorGUI.Background.width, ((curEditorState.zoomPos.y - curEditorState.canvasRect.height) * curEditorState.zoom + curEditorState.panOffset.y) / NodeEditorGUI.Background.height); // Amount of tiles Vector2 tileAmount = new Vector2(Mathf.Round(curEditorState.canvasRect.width * curEditorState.zoom) / NodeEditorGUI.Background.width, Mathf.Round(curEditorState.canvasRect.height * curEditorState.zoom) / NodeEditorGUI.Background.height); // Draw tiled background GUI.DrawTextureWithTexCoords(curEditorState.canvasRect, NodeEditorGUI.Background, new Rect(tileOffset, tileAmount)); } // Handle input events NodeEditorInputSystem.HandleInputEvents(curEditorState); HandleMultipleSelect(); if (Event.current.type != EventType.Layout) { curEditorState.ignoreInput = new List <Rect>(); } // We're using a custom scale method, as default one is messing up clipping rect Rect canvasRect = curEditorState.canvasRect; curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale(ref canvasRect, curEditorState.zoomPos, curEditorState.zoom, NodeEditorGUI.isEditorWindow, false); // ---- BEGIN SCALE ---- // Some features which require zoomed drawing: if (curEditorState.navigate) { // Draw a curve to the origin/active node for orientation purposes Vector2 startPos = (curEditorState.selectedNodes.Count > 0? curEditorState.selectedNodes[0].rect.center : curEditorState.panOffset) + curEditorState.zoomPanAdjust; Vector2 endPos = Event.current.mousePosition; RTEditorGUI.DrawLine(startPos, endPos, Color.green, null, 3); RepaintClients(); } if (curEditorState.connectKnob != null) { // Draw the currently drawn connection curEditorState.connectKnob.DrawConnection(Event.current.mousePosition); RepaintClients(); } // Draw the groups below everything else for (int groupCnt = 0; groupCnt < curNodeCanvas.groups.Count; groupCnt++) { NodeGroup group = curNodeCanvas.groups[groupCnt]; if (Event.current.type == EventType.Layout) { group.isClipped = !curEditorState.canvasViewport.Overlaps(group.fullAABBRect); } if (!group.isClipped) { group.DrawGroup(); } } // Push the active node to the top of the draw order. if (Event.current.type == EventType.Layout && curEditorState.selectedNodes.Count > 0) { foreach (var node in curEditorState.selectedNodes) { curNodeCanvas.nodes.Remove(node); curNodeCanvas.nodes.Add(node); } } // Draw the transitions and connections. Has to be drawn before nodes as transitions originate from node centers for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { curNodeCanvas.nodes[nodeCnt].DrawConnections(); } // Draw the nodes for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { Node node = curNodeCanvas.nodes[nodeCnt]; if (Event.current.type == EventType.Layout) { node.isClipped = !curEditorState.canvasViewport.Overlaps(curNodeCanvas.nodes[nodeCnt].fullAABBRect); } if (!node.isClipped || node.ForceGUIDawOffScreen) { node.DrawNode(); if (Event.current.type == EventType.Repaint) { node.DrawKnobs(); } } } // ---- END SCALE ---- // End scaling group GUIScaleUtility.EndScale(); // Handle input events with less priority than node GUI controls NodeEditorInputSystem.HandleLateInputEvents(curEditorState); EndEditingCanvas(); }
/// <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; }
/// <summary> /// Draws the Node Canvas on the screen in the rect specified by editorState without one-time wrappers like GUISkin and OverlayGUI. Made for nested Canvases (WIP) /// </summary> public static void DrawSubCanvas (NodeCanvas nodeCanvas, NodeEditorState editorState) { if (!editorState.drawing) return; // Store and restore later on in case of this being a nested Canvas NodeCanvas prevNodeCanvas = curNodeCanvas; NodeEditorState prevEditorState = curEditorState; curNodeCanvas = nodeCanvas; curEditorState = editorState; if (Event.current.type == EventType.Repaint) { // Draw Background when Repainting GUI.BeginClip (curEditorState.canvasRect); float width = NodeEditorGUI.Background.width / curEditorState.zoom; float height = NodeEditorGUI.Background.height / curEditorState.zoom; Vector2 offset = curEditorState.zoomPos + curEditorState.panOffset/curEditorState.zoom; offset = new Vector2 (offset.x%width - width, offset.y%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++) { GUI.DrawTexture (new Rect (offset.x + x*width, offset.y + y*height, width, height), NodeEditorGUI.Background); } } GUI.EndClip (); } // Check the inputs InputEvents (); if (Event.current.type != EventType.Layout) curEditorState.ignoreInput = new List<Rect> (); // We're using a custom scale method, as default one is messing up clipping rect Rect canvasRect = curEditorState.canvasRect; curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale (ref canvasRect, curEditorState.zoomPos, curEditorState.zoom, false); //GUILayout.Label ("Scaling is Great!"); -> TODO: Test by changing the last bool parameter // ---- BEGIN SCALE ---- // Some features which require drawing (zoomed) if (curEditorState.navigate) { // Draw a curve to the origin/active node for orientation purposes RTEditorGUI.DrawLine ((curEditorState.selectedNode != null? curEditorState.selectedNode.rect.center : curEditorState.panOffset) + curEditorState.zoomPanAdjust, ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.black, null, 3); RepaintClients (); } if (curEditorState.connectOutput != null) { // Draw the currently drawn connection NodeOutput output = curEditorState.connectOutput; Vector2 startPos = output.GetGUIKnob ().center; Vector2 endPos = ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom; Vector2 endDir = output.GetDirection (); NodeEditorGUI.DrawConnection (startPos, endDir, endPos, NodeEditorGUI.GetSecondConnectionVector (startPos, endPos, endDir), ConnectionTypes.GetTypeData (output.type, true).Color); RepaintClients (); } if (curEditorState.makeTransition != null) { // Draw the currently made transition RTEditorGUI.DrawLine (curEditorState.makeTransition.rect.center + curEditorState.zoomPanAdjust, ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.grey, null, 3); RepaintClients (); } // Push the active node at the bottom of the draw order. if (Event.current.type == EventType.Layout && curEditorState.selectedNode != null) { curNodeCanvas.nodes.Remove (curEditorState.selectedNode); curNodeCanvas.nodes.Add (curEditorState.selectedNode); } // Draw the transitions and connections. Has to be drawn before nodes as transitions originate from node centers foreach (Node node in curNodeCanvas.nodes) node.DrawConnections (); // Draw the nodes foreach (Node node in curNodeCanvas.nodes) { node.DrawNode (); if (Event.current.type == EventType.Repaint) node.DrawKnobs (); } // ---- END SCALE ---- // End scaling group GUIScaleUtility.EndScale (); // Check events with less priority than node GUI controls LateEvents (); curNodeCanvas = prevNodeCanvas; curEditorState = prevEditorState; }
/// <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> /// 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)); }
/// <summary> /// CreateWorkingCopy a working copy of the canvas and each editorState. This will break the link to the canvas asset and thus all changes made to the working copy have to be explicitly saved. /// Check compressed if the copy is not intended for useage but for storage, this will leave the Inputs and Outputs list of Node empty /// </summary> public static void CreateWorkingCopy(ref NodeCanvas nodeCanvas, NodeEditorState[] editorStates, bool compressed) { nodeCanvas = Clone(nodeCanvas); // Take each SO, make a clone of it and store both versions in the respective list // This will only iterate over the 'source instances' List <ScriptableObject> allSOs = new List <ScriptableObject> (); List <ScriptableObject> clonedSOs = new List <ScriptableObject> (); foreach (Node node in nodeCanvas.nodes) { node.CheckNodeKnobMigration(); Node clonedNode = AddClonedSO(allSOs, clonedSOs, node); foreach (NodeKnob knob in clonedNode.nodeKnobs) { // Clone NodeKnobs NodeKnob clonedKnob = AddClonedSO(allSOs, clonedSOs, knob); // Clone additional scriptableObjects ScriptableObject[] additionalKnobSOs = clonedKnob.GetScriptableObjects(); foreach (ScriptableObject so in additionalKnobSOs) { AddClonedSO(allSOs, clonedSOs, so); } } // Clone additional scriptableObjects ScriptableObject[] additionalNodeSOs = clonedNode.GetScriptableObjects(); foreach (ScriptableObject so in additionalNodeSOs) { AddClonedSO(allSOs, clonedSOs, so); } } // Replace every reference to any of the initial SOs of the first list with the respective clones of the second list for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++) { // Clone Nodes, structural content and additional scriptableObjects Node clonedNode = nodeCanvas.nodes[nodeCnt] = ReplaceSO(allSOs, clonedSOs, nodeCanvas.nodes[nodeCnt]); // We're going to restore these from NodeKnobs if desired (!compressed) clonedNode.Inputs = new List <NodeInput> (); clonedNode.Outputs = new List <NodeOutput> (); for (int knobCnt = 0; knobCnt < clonedNode.nodeKnobs.Count; knobCnt++) { // Clone generic NodeKnobs NodeKnob clonedKnob = clonedNode.nodeKnobs[knobCnt] = ReplaceSO(allSOs, clonedSOs, clonedNode.nodeKnobs[knobCnt]); clonedKnob.body = clonedNode; if (!compressed) { // Add NodeInputs and NodeOutputs to the apropriate lists in Node if desired (!compressed) if (clonedKnob is NodeInput) { clonedNode.Inputs.Add(clonedKnob as NodeInput); } else if (clonedKnob is NodeOutput) { clonedNode.Outputs.Add(clonedKnob as NodeOutput); } } // Replace additional scriptableObjects in the NodeKnob clonedKnob.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); } // Replace additional scriptableObjects in the Node clonedNode.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); } // Also create working copies for specified editorStates, if any // Needs to be in the same function as the EditorState references nodes from the NodeCanvas if (editorStates != null) { for (int stateCnt = 0; stateCnt < editorStates.Length; stateCnt++) { if (editorStates[stateCnt] == null) { continue; } NodeEditorState clonedState = editorStates[stateCnt] = Clone(editorStates[stateCnt]); clonedState.canvas = nodeCanvas; clonedState.focusedNode = null; clonedState.selectedNode = clonedState.selectedNode != null?ReplaceSO(allSOs, clonedSOs, clonedState.selectedNode) : null; clonedState.makeTransition = null; clonedState.connectOutput = null; } } }
public NodeEditorMenuCallback (string Message, NodeCanvas nodecanvas, NodeEditorState editorState) { message = Message; canvas = nodecanvas; editor = editorState; contextClickPos = Event.current.mousePosition; }
/// <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, Action repaint) { if (!editorState.drawing) { return; } curNodeCanvas = nodeCanvas; curEditorState = editorState; if (repaint != null) { Repaint += repaint; } // 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 DrawLine(curEditorState.activeNode != null? curEditorState.activeNode.rect.center + curEditorState.zoomPanAdjust : curEditorState.panOffset, ScreenToGUIPos(mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.black, null, 3); if (Repaint != null) { Repaint(); } } if (curEditorState.connectOutput != null) { // Draw the currently drawn connection DrawConnection(curEditorState.connectOutput.GetGUIKnob().center, ScreenToGUIPos(mousePos) + curEditorState.zoomPos * curEditorState.zoom, ConnectionTypes.GetTypeData(curEditorState.connectOutput.type).col); if (Repaint != null) { Repaint(); } } if (curEditorState.makeTransition != null) { // Draw the currently made transition DrawLine(curEditorState.makeTransition.rect.center + curEditorState.zoomPanAdjust, ScreenToGUIPos(mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.grey, null, 3); if (Repaint != null) { Repaint(); } } // Draw the Node 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(); } for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { curNodeCanvas.nodes [nodeCnt].DrawTransitions(); } // 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 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, Repaint); 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); }
public virtual void OnSaveEditorState (NodeEditorState editorState) {}
/// <summary> /// CreateWorkingCopy a working copy of the canvas and each editorState. This will break the link to the canvas asset and thus all changes made to the working copy have to be explicitly saved. /// Check compressed if the copy is not intended for useage but for storage, this will leave the Inputs and Outputs list of Node empty /// </summary> public static void CreateWorkingCopy(ref NodeCanvas nodeCanvas, NodeEditorState[] editorStates, bool compressed) { nodeCanvas = Clone(nodeCanvas); // Take each SO, make a clone of it and store both versions in the respective list // This will only iterate over the 'source instances' List <ScriptableObject> allSOs = new List <ScriptableObject> (); List <ScriptableObject> clonedSOs = new List <ScriptableObject> (); for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++) { Node node = nodeCanvas.nodes[nodeCnt]; node.CheckNodeKnobMigration(); Node clonedNode = (Node)AddClonedSO(allSOs, clonedSOs, node); for (int knobCnt = 0; knobCnt < clonedNode.nodeKnobs.Count; knobCnt++) { // Clone NodeKnobs // Debug.Log ("Cloned " + knobCnt + " " + (clonedNode.nodeKnobs[knobCnt] == null? "null" : clonedNode.nodeKnobs[knobCnt].name) + " on node " + node.name); AddClonedSO(allSOs, clonedSOs, clonedNode.nodeKnobs[knobCnt]); // Clone additional scriptableObjects ScriptableObject[] additionalKnobSOs = clonedNode.nodeKnobs[knobCnt].GetScriptableObjects(); foreach (ScriptableObject so in additionalKnobSOs) { AddClonedSO(allSOs, clonedSOs, so); } } for (int transCnt = 0; transCnt < clonedNode.transitions.Count; transCnt++) { // Clone Transitions Transition trans = clonedNode.transitions[transCnt]; if (trans.startNode == node) { AddClonedSO(allSOs, clonedSOs, trans); // Debug.Log ("Did copy Transition " + trans.name + " because its Node " + clonedNode.name + " is the start node!"); } else { // Debug.Log ("Did NOT copy Transition " + trans.name + " because its Node " + clonedNode.name + " is NOT the start node (" + trans.startNode.name + ")!"); clonedNode.transitions.RemoveAt(transCnt); transCnt--; } } // Clone additional scriptableObjects ScriptableObject[] additionalNodeSOs = clonedNode.GetScriptableObjects(); foreach (ScriptableObject so in additionalNodeSOs) { AddClonedSO(allSOs, clonedSOs, so); } } // Replace every reference to any of the initial SOs of the first list with the respective clones of the second list nodeCanvas.currentNode = ReplaceSO(allSOs, clonedSOs, nodeCanvas.currentNode); nodeCanvas.currentTransition = ReplaceSO(allSOs, clonedSOs, nodeCanvas.currentTransition); for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++) { // Clone Nodes, structural content and additional scriptableObjects Node node = nodeCanvas.nodes[nodeCnt]; Node clonedNode = nodeCanvas.nodes[nodeCnt] = ReplaceSO(allSOs, clonedSOs, node); // We're going to restore these from NodeKnobs if desired (!compressed) clonedNode.Inputs = new List <NodeInput> (); clonedNode.Outputs = new List <NodeOutput> (); for (int knobCnt = 0; knobCnt < clonedNode.nodeKnobs.Count; knobCnt++) { // Clone generic NodeKnobs NodeKnob knob = clonedNode.nodeKnobs[knobCnt] = ReplaceSO(allSOs, clonedSOs, clonedNode.nodeKnobs[knobCnt]); knob.body = clonedNode; // Replace additional scriptableObjects in the NodeKnob knob.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); if (!compressed) { // Add NodeInputs and NodeOutputs to the apropriate lists in Node if desired (!compressed) if (knob is NodeInput) { clonedNode.Inputs.Add(knob as NodeInput); } else if (knob is NodeOutput) { clonedNode.Outputs.Add(knob as NodeOutput); } } } for (int transCnt = 0; transCnt < clonedNode.transitions.Count; transCnt++) { // Clone transitions Transition trans = clonedNode.transitions[transCnt]; if (trans.startNode != node) { continue; } trans = clonedNode.transitions[transCnt] = ReplaceSO(allSOs, clonedSOs, trans); if (trans == null) { Debug.LogError("Could not copy transition number " + transCnt + " of Node " + clonedNode.name + "!"); continue; } // Debug.Log ("Did replace contents of Transition " + trans.name + " because its Node " + clonedNode.name + " is the start node!"); trans.startNode = ReplaceSO(allSOs, clonedSOs, trans.startNode); trans.endNode = ReplaceSO(allSOs, clonedSOs, trans.endNode); if (!compressed) { trans.endNode.transitions.Add(trans); } } // Replace additional scriptableObjects in the Node node.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); } // Also create working copies for specified editorStates, if any // Needs to be in the same function as the EditorState references nodes from the NodeCanvas if (editorStates != null) { for (int stateCnt = 0; stateCnt < editorStates.Length; stateCnt++) { if (editorStates[stateCnt] == null) { continue; } NodeEditorState state = editorStates[stateCnt] = Clone(editorStates[stateCnt]); state.canvas = nodeCanvas; state.focusedNode = null; state.selectedNode = state.selectedNode != null?ReplaceSO(allSOs, clonedSOs, state.selectedNode) : null; state.makeTransition = null; state.connectOutput = null; } } }
public void SetCanvas(NodeCanvas canvas) { nodeCanvas = canvas; editorState = NodeEditorSaveManager.ExtractEditorState(nodeCanvas, MainEditorStateIdentifier); NodeEditor.RepaintClients(); }
/// <summary> /// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path /// </summary> public void LoadNodeCanvas (string path) { // Load the NodeCanvas mainNodeCanvas = NodeEditor.LoadNodeCanvas (path); if (mainNodeCanvas == null) { NewNodeCanvas (); return; } // Load the associated MainEditorState List<NodeEditorState> editorStates = NodeEditor.LoadEditorStates (path); if (editorStates.Count == 0) mainEditorState = CreateInstance<NodeEditorState> (); else { mainEditorState = editorStates.Find (x => x.name == "MainEditorState"); if (mainEditorState == null) mainEditorState = editorStates[0]; } mainEditorState.Canvas = mainNodeCanvas; OpenedCanvasPath = path; NodeEditor.RecalculateAll (mainNodeCanvas); //SaveCache (); 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 = ""; }
/// <summary> /// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path /// </summary> public void LoadNodeCanvas(string path) { // Load the NodeCanvas mainNodeCanvas = NodeEditorSaveManager.LoadNodeCanvas (path, true); if (mainNodeCanvas == null) { Debug.Log ("Error loading NodeCanvas from '" + path + "'!"); NewNodeCanvas (); return; } // Load the associated MainEditorState List<NodeEditorState> editorStates = NodeEditorSaveManager.LoadEditorStates (path, true); if (editorStates.Count == 0) { mainEditorState = ScriptableObject.CreateInstance<NodeEditorState> (); Debug.LogError ("The save file '" + path + "' did not contain an associated NodeEditorState!"); } else { mainEditorState = editorStates.Find (x => x.name == "MainEditorState"); if (mainEditorState == null) mainEditorState = editorStates[0]; } mainEditorState.canvas = mainNodeCanvas; openedCanvasPath = path; NodeEditor.RecalculateAll (mainNodeCanvas); SaveCache (); Repaint (); }
/// <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 (curEditorState.focusedNode != null) { curEditorState.focusedNode.Delete(); } break; case "duplicateNode": if (curEditorState.focusedNode != null) { ContextCallback(new callbackObject(curEditorState.focusedNode.GetID, curNodeCanvas, curEditorState)); Node duplicatedNode = curNodeCanvas.nodes [curNodeCanvas.nodes.Count - 1]; curEditorState.focusedNode = duplicatedNode; curEditorState.dragNode = true; curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.panWindow = false; } break; case "startTransition": if (curEditorState.focusedNode != null) { curEditorState.makeTransition = curEditorState.focusedNode; curEditorState.connectOutput = null; } curEditorState.dragNode = false; curEditorState.panWindow = false; break; default: Vector2 createPos = ScreenToGUIPos(mousePos); Node node = NodeTypes.getDefaultNode(cbObj.message); if (node == null) { break; } bool acceptTransitions = NodeTypes.nodes [node].transitions; node = node.Create(createPos); node.InitBase(); NodeEditorCallbacks.IssueOnAddNode(node); if (curEditorState.connectOutput != null) { // If nodeOutput is defined, link it to the first input of the same type foreach (NodeInput input in node.Inputs) { if (Node.CanApplyConnection(curEditorState.connectOutput, input)) { // If it can connect (type is equals, it does not cause recursion, ...) Node.ApplyConnection(curEditorState.connectOutput, input); break; } } } else if (acceptTransitions && curEditorState.makeTransition != null) { Node.CreateTransition(curEditorState.makeTransition, node); } curEditorState.makeTransition = null; curEditorState.connectOutput = null; curEditorState.dragNode = false; curEditorState.panWindow = false; break; } if (NodeEditor.Repaint != null) { NodeEditor.Repaint(); } }
/// <summary> /// Creates and opens a new empty node canvas /// </summary> public void NewNodeCanvas() { // New NodeCanvas mainNodeCanvas = CreateInstance<NodeCanvas> (); mainNodeCanvas.name = "New Canvas"; // New NodeEditorState mainEditorState = CreateInstance<NodeEditorState> (); mainEditorState.canvas = mainNodeCanvas; mainEditorState.name = "MainEditorState"; openedCanvasPath = ""; SaveCache (); }
/// <summary> /// Draws the Node Canvas on the screen in the rect specified by editorState /// </summary> public static void DrawSubCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState) { if (!editorState.drawing) { return; } NodeCanvas prevNodeCanvas = curNodeCanvas; NodeEditorState prevEditorState = curEditorState; curNodeCanvas = nodeCanvas; curEditorState = editorState; if (Event.current.type == EventType.Repaint) { // Draw Background when Repainting GUI.BeginClip(curEditorState.canvasRect); float width = NodeEditorGUI.Background.width / curEditorState.zoom; float height = NodeEditorGUI.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, NodeEditorGUI.Background); } } GUI.EndClip(); } // Check the inputs InputEvents(curEditorState.ignoreInput); curEditorState.ignoreInput = new List <Rect> (); // We're using a custom scale methode, as default one is messing up clipping rect Rect canvasRect = curEditorState.canvasRect; curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale(ref canvasRect, curEditorState.zoomPos, curEditorState.zoom, true); //GUILayout.Label ("Scaling is Great!"); -> Test by changin the last bool parameter // ---- BEGIN SCALE ---- // Some features which require drawing (zoomed) if (curEditorState.navigate) { // Draw a curve to the origin/active node for orientation purposes NodeEditorGUI.DrawLine(curEditorState.activeNode != null? curEditorState.activeNode.rect.center + curEditorState.zoomPanAdjust : curEditorState.panOffset, ScreenToGUIPos(mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.black, null, 3); if (Repaint != null) { Repaint(); } } if (curEditorState.connectOutput != null) { // Draw the currently drawn connection NodeOutput output = curEditorState.connectOutput; DrawConnection(output.GetGUIKnob().center, output.GetDirection(), ScreenToGUIPos(mousePos) + curEditorState.zoomPos * curEditorState.zoom, Vector2.right, ConnectionTypes.GetTypeData(output.type).col); if (Repaint != null) { Repaint(); } } if (curEditorState.makeTransition != null) { // Draw the currently made transition NodeEditorGUI.DrawLine(curEditorState.makeTransition.rect.center + curEditorState.zoomPanAdjust, ScreenToGUIPos(mousePos) + curEditorState.zoomPos * curEditorState.zoom, Color.grey, null, 3); if (Repaint != null) { Repaint(); } } // Push the active cell at the bottom of the draw order. if (Event.current.type == EventType.Layout && curEditorState.activeNode != null) { curNodeCanvas.nodes.Remove(curEditorState.activeNode); curNodeCanvas.nodes.Add(curEditorState.activeNode); } // Draw the transitions. Has to be called before nodes as transitions originate from node centers for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { curNodeCanvas.nodes [nodeCnt].DrawTransitions(); } for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { curNodeCanvas.nodes [nodeCnt].DrawConnections(); } // Draw the nodes for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { curNodeCanvas.nodes [nodeCnt].DrawNode(); curNodeCanvas.nodes [nodeCnt].DrawKnobs(); } // ---- END SCALE ---- // End scaling group GUIScaleUtility.EndScale(); // Check events with less priority than node GUI controls LateEvents(curEditorState.ignoreInput); curNodeCanvas = prevNodeCanvas; curEditorState = prevEditorState; }
private void LoadCache() { string lastSessionName = EditorPrefs.GetString ("NodeEditorLastSession"); string path = tempSessionPath + "/LastSession.asset"; mainNodeCanvas = NodeEditorSaveManager.LoadNodeCanvas (path, false); if (mainNodeCanvas == null) NewNodeCanvas (); else { mainNodeCanvas.name = lastSessionName; List<NodeEditorState> editorStates = NodeEditorSaveManager.LoadEditorStates (path, false); if (editorStates == null || editorStates.Count == 0 || (mainEditorState = editorStates.Find (x => x.name == "MainEditorState")) == null ) { // New NodeEditorState mainEditorState = CreateInstance<NodeEditorState> (); mainEditorState.canvas = mainNodeCanvas; mainEditorState.name = "MainEditorState"; NodeEditorSaveManager.AddSubAsset (mainEditorState, path); AssetDatabase.SaveAssets (); AssetDatabase.Refresh (); } } }
/// <summary> /// Draws the Node Canvas on the screen in the rect specified by editorState without one-time wrappers like GUISkin and OverlayGUI. Made for nested Canvases (WIP) /// </summary> private static void DrawSubCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState) { if (!editorState.drawing) { return; } BeginEditingCanvas(nodeCanvas, editorState); if (Event.current.type == EventType.Repaint) { // Draw Background when Repainting // Offset from origin in tile units Vector2 tileOffset = new Vector2(-(curEditorState.zoomPos.x * curEditorState.zoom + curEditorState.panOffset.x) / NodeEditorGUI.Background.width, ((curEditorState.zoomPos.y - curEditorState.canvasRect.height) * curEditorState.zoom + curEditorState.panOffset.y) / NodeEditorGUI.Background.height); // Amount of tiles Vector2 tileAmount = new Vector2(Mathf.Round(curEditorState.canvasRect.width * curEditorState.zoom) / NodeEditorGUI.Background.width, Mathf.Round(curEditorState.canvasRect.height * curEditorState.zoom) / NodeEditorGUI.Background.height); // Draw tiled background GUI.DrawTextureWithTexCoords(curEditorState.canvasRect, NodeEditorGUI.Background, new Rect(tileOffset, tileAmount)); } // Handle input events NodeEditorInputSystem.HandleInputEvents(curEditorState); if (Event.current.type != EventType.Layout) { curEditorState.ignoreInput = new List <Rect> (); } // We're using a custom scale method, as default one is messing up clipping rect Rect canvasRect = curEditorState.canvasRect; curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale(ref canvasRect, curEditorState.zoomPos, curEditorState.zoom, NodeEditorGUI.isEditorWindow, false); // ---- BEGIN SCALE ---- // Some features which require zoomed drawing: if (curEditorState.navigate) { // Draw a curve to the origin/active node for orientation purposes Vector2 startPos = (curEditorState.selectedNode != null? curEditorState.selectedNode.rect.center : curEditorState.panOffset) + curEditorState.zoomPanAdjust; Vector2 endPos = Event.current.mousePosition; RTEditorGUI.DrawLine(startPos, endPos, Color.green, null, 3); RepaintClients(); } if (curEditorState.connectOutput != null) { // Draw the currently drawn connection NodeOutput output = curEditorState.connectOutput; Vector2 startPos = output.GetGUIKnob().center; Vector2 startDir = output.GetDirection(); Vector2 endPos = Event.current.mousePosition; Vector2 endDir = -startDir; // NodeEditorGUI.GetSecondConnectionVector (startPos, endPos, startDir); <- causes unpleasant jumping when switching polarity NodeEditorGUI.OptimiseBezierDirections(startPos, ref startDir, endPos, ref endDir); NodeEditorGUI.DrawConnection(startPos, startDir, endPos, endDir, output.typeData.Color); RepaintClients(); } // Draw the groups below everything else for (int groupCnt = 0; groupCnt < curNodeCanvas.groups.Count; groupCnt++) { curNodeCanvas.groups [groupCnt].DrawGroup(); } // Push the active node to the top of the draw order. if (Event.current.type == EventType.Layout && curEditorState.selectedNode != null) { curNodeCanvas.nodes.Remove(curEditorState.selectedNode); curNodeCanvas.nodes.Add(curEditorState.selectedNode); } // Draw the transitions and connections. Has to be drawn before nodes as transitions originate from node centers for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { curNodeCanvas.nodes [nodeCnt].DrawConnections(); } // Draw the nodes for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++) { Node node = curNodeCanvas.nodes [nodeCnt]; node.DrawNode(); if (Event.current.type == EventType.Repaint) { node.DrawKnobs(); } } // ---- END SCALE ---- // End scaling group GUIScaleUtility.EndScale(); // Handle input events with less priority than node GUI controls NodeEditorInputSystem.HandleLateInputEvents(curEditorState); EndEditingCanvas(); }
public NodeEditorMenuCallback(string Message, NodeCanvas nodecanvas, NodeEditorState editorState) { message = Message; canvas = nodecanvas; editor = editorState; }
public static void EndEditingCanvas() { curNodeCanvas = editCanvasStack.Pop(); curEditorState = editEditorStateStack.Pop(); }
/// <summary> /// Checks if any transitions of the passed node have their conditions met. /// In that case returns the node the transition points to, else returns the passed node. /// </summary> public static void StopTransitioning(NodeEditorState editorState) { }
public virtual void OnLoadEditorState(NodeEditorState editorState) { }
private static void WaitForTransitions(NodeEditorState transitioningEditorState) { }
/// <summary> /// Draws the NodeGroup /// </summary> public void DrawGroup() { if (backgroundStyle == null) { GenerateStyles(); } NodeEditorState state = NodeEditor.curEditorState; // Create a rect that is adjusted to the editor zoom Rect groupRect = rect; groupRect.position += state.zoomPanAdjust + state.panOffset; // Resize handles //Rect leftSideRect = new Rect(groupRect.x, groupRect.y, borderWidth, groupRect.height); //Rect rightSideRect = new Rect(groupRect.x + groupRect.width - borderWidth, groupRect.y, borderWidth, groupRect.height); //Rect topSideRect = new Rect(groupRect.x, groupRect.y, groupRect.width, borderWidth); //Rect bottomSideRect = new Rect(groupRect.x, groupRect.y + groupRect.height - borderWidth, groupRect.width, borderWidth); //GUI.Box(leftSideRect, GUIContent.none, dragHandleStyle); //GUI.Box(rightSideRect, GUIContent.none, dragHandleStyle); //GUI.Box(topSideRect, GUIContent.none, dragHandleStyle); //GUI.Box(bottomSideRect, GUIContent.none, dragHandleStyle); if (state.activeGroup == this && state.resizeGroup) { // Highlight the currently resized border Rect handleRect = getBorderRect(rect, NodeGroup.resizeDir); handleRect.position += state.zoomPanAdjust + state.panOffset; GUI.Box(handleRect, GUIContent.none, opBackgroundStyle); } // Body Rect groupBodyRect = bodyRect; groupBodyRect.position += state.zoomPanAdjust + state.panOffset; GUI.Box(groupBodyRect, GUIContent.none, backgroundStyle); // Header Rect groupHeaderRect = headerRect; groupHeaderRect.position += state.zoomPanAdjust + state.panOffset; GUILayout.BeginArea(groupHeaderRect, headerFree? GUIStyle.none : altBackgroundStyle); GUILayout.BeginHorizontal(); GUILayout.Space(8); // Header Title if (edit) { title = GUILayout.TextField(title, headerTitleEditStyle, GUILayout.MinWidth(40)); } else { GUILayout.Label(title, headerTitleStyle, GUILayout.MinWidth(40)); } GUILayout.Space(10); // Header Color Edit #if UNITY_EDITOR if (edit && !Application.isPlaying) { GUILayout.Space(10); color = UnityEditor.EditorGUILayout.ColorField(color); } #endif GUILayout.FlexibleSpace(); // Edit Button if (GUILayout.Button("E", new GUILayoutOption [] { GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false) })) { edit = !edit; } GUILayout.EndHorizontal(); GUILayout.EndArea(); }
public callbackObject(string Message, NodeCanvas nodecanvas, NodeEditorState editorState, Node Node, NodeOutput NodeOutput) { message = Message; canvas = nodecanvas; editor = editorState; node = Node; nodeOutput = NodeOutput; }