Example #1
0
 /// <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 ();
		}
Example #5
0
        /// <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);
 }
Example #7
0
        /// <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;
        }
Example #8
0
 /// <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)));
 }
Example #9
0
 /// <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;
 }
Example #10
0
        /// <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();
        }
Example #11
0
        /// <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;
        }
Example #12
0
 /// <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;
     }
 }
Example #14
0
        /// <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) {}
Example #17
0
		/// <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 ();
		}
Example #18
0
        /// <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 ();
        }
Example #19
0
        /// <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();
        }
Example #20
0
 public callbackObject(string Message, NodeCanvas nodecanvas, NodeEditorState editorState)
 {
     message = Message;
     canvas  = nodecanvas;
     editor  = editorState;
 }
Example #21
0
 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);
        }
Example #23
0
        /// <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)
 {
 }
Example #25
0
        /// <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);
        }
Example #26
0
        /// <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();
        }
Example #27
0
 /// <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;
		}
Example #29
0
        /// <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));
		}
Example #31
0
        /// <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;
			}
Example #33
0
        /// <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) {}
Example #35
0
        /// <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();
 }
Example #37
0
		/// <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 ();
		}
Example #38
0
 /// <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 = "";
 }
Example #39
0
        /// <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 ();
        }
Example #40
0
        /// <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();
            }
        }
Example #41
0
        /// <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 ();
        }
Example #42
0
        /// <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;
        }
Example #43
0
 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();
        }
Example #45
0
 public NodeEditorMenuCallback(string Message, NodeCanvas nodecanvas, NodeEditorState editorState)
 {
     message = Message;
     canvas  = nodecanvas;
     editor  = editorState;
 }
 public static void EndEditingCanvas()
 {
     curNodeCanvas  = editCanvasStack.Pop();
     curEditorState = editEditorStateStack.Pop();
 }
Example #47
0
 /// <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)
 {
 }
Example #49
0
 private static void WaitForTransitions(NodeEditorState transitioningEditorState)
 {
 }
Example #50
0
        /// <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();
        }
Example #51
0
 public callbackObject(string Message, NodeCanvas nodecanvas, NodeEditorState editorState, Node Node, NodeOutput NodeOutput)
 {
     message = Message;
     canvas = nodecanvas;
     editor = editorState;
     node = Node;
     nodeOutput = NodeOutput;
 }