Beispiel #1
0
        /// <summary> Show right-click context menu for selected nodes </summary>
        public void ShowNodeContextMenu()
        {
            GenericMenu contextMenu = new GenericMenu();

            // If only one node is selected
            if (Selection.objects.Length == 1 && Selection.activeObject is Siccity.XNode.Node)
            {
                Siccity.XNode.Node node = Selection.activeObject as Siccity.XNode.Node;
                contextMenu.AddItem(new GUIContent("Move To Top"), false, () => {
                    int index;
                    while ((index = graph.nodes.IndexOf(node)) != graph.nodes.Count - 1)
                    {
                        graph.nodes[index]     = graph.nodes[index + 1];
                        graph.nodes[index + 1] = node;
                    }
                });
            }

            contextMenu.AddItem(new GUIContent("Duplicate"), false, DublicateSelectedNodes);
            contextMenu.AddItem(new GUIContent("Remove"), false, RemoveSelectedNodes);

            // If only one node is selected
            if (Selection.objects.Length == 1 && Selection.activeObject is Siccity.XNode.Node)
            {
                Siccity.XNode.Node node = Selection.activeObject as Siccity.XNode.Node;
                AddCustomContextMenuItems(contextMenu, node);
            }

            contextMenu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero));
        }
Beispiel #2
0
        public void DeselectNode(Siccity.XNode.Node node)
        {
            List <Object> selection = new List <Object>(Selection.objects);

            selection.Remove(node);
            Selection.objects = selection.ToArray();
        }
Beispiel #3
0
 /// <summary> Remove nodes in the graph in Selection.objects</summary>
 public void RemoveSelectedNodes() {
     foreach (UnityEngine.Object item in Selection.objects) {
         if (item is Siccity.XNode.Node) {
             Siccity.XNode.Node node = item as Siccity.XNode.Node;
             graph.RemoveNode(node);
         }
     }
 }
Beispiel #4
0
 bool IsHoveringTitle(Siccity.XNode.Node node) {
     Vector2 mousePos = Event.current.mousePosition;
     //Get node position
     Vector2 nodePos = GridToWindowPosition(node.position);
     float width = 200;
     if (nodeWidths.ContainsKey(node)) width = nodeWidths[node];
     Rect windowRect = new Rect(nodePos, new Vector2(width / zoom, 30 / zoom));
     return windowRect.Contains(mousePos);
 }
Beispiel #5
0
 /// <summary> Make a field for a serialized property. Automatically displays relevant node port. </summary>
 public static void PropertyField(SerializedProperty property, GUIContent label, bool includeChildren = true, params GUILayoutOption[] options)
 {
     if (property == null)
     {
         throw new NullReferenceException();
     }
     Siccity.XNode.Node     node = property.serializedObject.targetObject as Siccity.XNode.Node;
     Siccity.XNode.NodePort port = node.GetPort(property.name);
     PropertyField(property, label, port, includeChildren);
 }
Beispiel #6
0
 public void SelectNode(Siccity.XNode.Node node, bool add)
 {
     if (add)
     {
         List <Object> selection = new List <Object>(Selection.objects);
         selection.Add(node);
         Selection.objects = selection.ToArray();
     }
     else
     {
         Selection.objects = new Object[] { node }
     };
 }
Beispiel #7
0
        /// <summary> Automatically delete Node sub-assets before deleting their script.
        /// <para/> This is important to do, because you can't delete null sub assets. </summary>
        private static AssetDeleteResult OnWillDeleteAsset(string path, RemoveAssetOptions options)
        {
            // Get the object that is requested for deletion
            UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath <UnityEngine.Object> (path);

            // If we aren't deleting a script, return
            if (!(obj is UnityEditor.MonoScript))
            {
                return(AssetDeleteResult.DidNotDelete);
            }

            // Check script type. Return if deleting a non-node script
            UnityEditor.MonoScript script     = obj as UnityEditor.MonoScript;
            System.Type            scriptType = script.GetClass();
            if (scriptType != typeof(Siccity.XNode.Node) && !scriptType.IsSubclassOf(typeof(Siccity.XNode.Node)))
            {
                return(AssetDeleteResult.DidNotDelete);
            }

            // Find all ScriptableObjects using this script
            string[] guids = AssetDatabase.FindAssets("t:" + scriptType);
            for (int i = 0; i < guids.Length; i++)
            {
                string   assetpath = AssetDatabase.GUIDToAssetPath(guids[i]);
                Object[] objs      = AssetDatabase.LoadAllAssetRepresentationsAtPath(assetpath);
                for (int k = 0; k < objs.Length; k++)
                {
                    Siccity.XNode.Node node = objs[k] as Siccity.XNode.Node;
                    if (node.GetType() == scriptType)
                    {
                        if (node != null && node.graph != null)
                        {
                            // Delete the node and notify the user
                            Debug.LogWarning(node.name + " of " + node.graph + " depended on deleted script and has been removed automatically.", node.graph);
                            node.graph.RemoveNode(node);
                        }
                    }
                }
            }
            // We didn't actually delete the script. Tell the internal system to carry on with normal deletion procedure
            return(AssetDeleteResult.DidNotDelete);
        }
Beispiel #8
0
        /// <summary> Dublicate selected nodes and select the dublicates </summary>
        public void DublicateSelectedNodes() {
            UnityEngine.Object[] newNodes = new UnityEngine.Object[Selection.objects.Length];
            Dictionary<Siccity.XNode.Node, Siccity.XNode.Node> substitutes = new Dictionary<Siccity.XNode.Node, Siccity.XNode.Node>();
            for (int i = 0; i < Selection.objects.Length; i++) {
                if (Selection.objects[i] is Siccity.XNode.Node) {
                    Siccity.XNode.Node srcNode = Selection.objects[i] as Siccity.XNode.Node;
                    if (srcNode.graph != graph) continue; // ignore nodes selected in another graph
                    Siccity.XNode.Node newNode = graph.CopyNode(srcNode);
                    substitutes.Add(srcNode, newNode);
                    newNode.position = srcNode.position + new Vector2(30, 30);
                    newNodes[i] = newNode;
                }
            }

            // Walk through the selected nodes again, recreate connections, using the new nodes
            for (int i = 0; i < Selection.objects.Length; i++) {
                if (Selection.objects[i] is Siccity.XNode.Node) {
                    Siccity.XNode.Node srcNode = Selection.objects[i] as Siccity.XNode.Node;
                    if (srcNode.graph != graph) continue; // ignore nodes selected in another graph
                    foreach (Siccity.XNode.NodePort port in srcNode.Ports) {
                        for (int c = 0; c < port.ConnectionCount; c++) {
                            Siccity.XNode.NodePort inputPort = port.direction == Siccity.XNode.NodePort.IO.Input ? port : port.GetConnection(c);
                            Siccity.XNode.NodePort outputPort = port.direction == Siccity.XNode.NodePort.IO.Output ? port : port.GetConnection(c);

                            if (substitutes.ContainsKey(inputPort.node) && substitutes.ContainsKey(outputPort.node)) {
                                Siccity.XNode.Node newNodeIn = substitutes[inputPort.node];
                                Siccity.XNode.Node newNodeOut = substitutes[outputPort.node];
                                newNodeIn.UpdateStaticPorts();
                                newNodeOut.UpdateStaticPorts();
                                inputPort = newNodeIn.GetInputPort(inputPort.fieldName);
                                outputPort = newNodeOut.GetOutputPort(outputPort.fieldName);
                            }
                            if (!inputPort.IsConnectedTo(outputPort)) inputPort.Connect(outputPort);
                        }
                    }
                }
            }
            Selection.objects = newNodes;
        }
Beispiel #9
0
        private void DrawNodes()
        {
            Event e = Event.current;

            if (e.type == EventType.Layout)
            {
                selectionCache = new List <UnityEngine.Object>(Selection.objects);
            }
            if (e.type == EventType.Repaint)
            {
                portConnectionPoints.Clear();
                nodeWidths.Clear();
            }

            //Active node is hashed before and after node GUI to detect changes
            int nodeHash = 0;

            System.Reflection.MethodInfo onValidate = null;
            if (Selection.activeObject != null && Selection.activeObject is Siccity.XNode.Node)
            {
                onValidate = Selection.activeObject.GetType().GetMethod("OnValidate");
                if (onValidate != null)
                {
                    nodeHash = Selection.activeObject.GetHashCode();
                }
            }

            BeginZoomed(position, zoom);

            Vector2 mousePos = Event.current.mousePosition;

            if (e.type != EventType.Layout)
            {
                hoveredNode = null;
                hoveredPort = null;
            }

            List <UnityEngine.Object> preSelection = preBoxSelection != null ? new List <UnityEngine.Object>(preBoxSelection) : new List <UnityEngine.Object>();

            //Save guiColor so we can revert it
            Color guiColor = GUI.color;

            for (int n = 0; n < graph.nodes.Count; n++)
            {
                // Skip null nodes. The user could be in the process of renaming scripts, so removing them at this point is not advisable.
                if (graph.nodes[n] == null)
                {
                    continue;
                }
                if (n >= graph.nodes.Count)
                {
                    return;
                }
                Siccity.XNode.Node node = graph.nodes[n];

                NodeEditor nodeEditor = NodeEditor.GetEditor(node);
                NodeEditor.portPositions = new Dictionary <Siccity.XNode.NodePort, Vector2>();

                //Get node position
                Vector2 nodePos = GridToWindowPositionNoClipped(node.position);

                GUILayout.BeginArea(new Rect(nodePos, new Vector2(nodeEditor.GetWidth(), 4000)));

                bool selected = selectionCache.Contains(graph.nodes[n]);

                if (selected)
                {
                    GUIStyle style          = new GUIStyle(NodeEditorResources.styles.nodeBody);
                    GUIStyle highlightStyle = new GUIStyle(NodeEditorResources.styles.nodeHighlight);
                    highlightStyle.padding = style.padding;
                    style.padding          = new RectOffset();
                    GUI.color = nodeEditor.GetTint();
                    GUILayout.BeginVertical(new GUIStyle(style));
                    GUI.color = NodeEditorPreferences.GetSettings().highlightColor;
                    GUILayout.BeginVertical(new GUIStyle(highlightStyle));
                }
                else
                {
                    GUIStyle style = NodeEditorResources.styles.nodeBody;
                    GUI.color = nodeEditor.GetTint();
                    GUILayout.BeginVertical(new GUIStyle(style));
                }

                GUI.color = guiColor;
                EditorGUI.BeginChangeCheck();

                //Draw node contents
                nodeEditor.OnNodeGUI();

                //Apply
                nodeEditor.serializedObject.ApplyModifiedProperties();

                //If user changed a value, notify other scripts through onUpdateNode
                if (EditorGUI.EndChangeCheck())
                {
                    if (NodeEditor.onUpdateNode != null)
                    {
                        NodeEditor.onUpdateNode(node);
                    }
                }

                if (e.type == EventType.Repaint)
                {
                    nodeWidths.Add(node, nodeEditor.GetWidth());

                    foreach (var kvp in NodeEditor.portPositions)
                    {
                        Vector2 portHandlePos = kvp.Value;
                        portHandlePos += node.position;
                        Rect rect = new Rect(portHandlePos.x - 8, portHandlePos.y - 8, 16, 16);
                        portConnectionPoints.Add(kvp.Key, rect);
                    }
                }

                GUILayout.EndVertical();
                if (selected)
                {
                    GUILayout.EndVertical();
                }

                if (e.type != EventType.Layout)
                {
                    //Check if we are hovering this node
                    Vector2 nodeSize   = GUILayoutUtility.GetLastRect().size;
                    Rect    windowRect = new Rect(nodePos, nodeSize);
                    if (windowRect.Contains(mousePos))
                    {
                        hoveredNode = node;
                    }

                    //If dragging a selection box, add nodes inside to selection
                    if (currentActivity == NodeActivity.DragGrid)
                    {
                        Vector2 startPos = GridToWindowPositionNoClipped(dragBoxStart);
                        Vector2 size     = mousePos - startPos;
                        if (size.x < 0)
                        {
                            startPos.x += size.x; size.x = Mathf.Abs(size.x);
                        }
                        if (size.y < 0)
                        {
                            startPos.y += size.y; size.y = Mathf.Abs(size.y);
                        }
                        Rect r = new Rect(startPos, size);
                        if (windowRect.Overlaps(r))
                        {
                            preSelection.Add(node);
                        }
                    }

                    //Check if we are hovering any of this nodes ports
                    //Check input ports
                    foreach (Siccity.XNode.NodePort input in node.Inputs)
                    {
                        //Check if port rect is available
                        if (!portConnectionPoints.ContainsKey(input))
                        {
                            continue;
                        }
                        Rect r = GridToWindowRect(portConnectionPoints[input]);
                        if (r.Contains(mousePos))
                        {
                            hoveredPort = input;
                        }
                    }
                    //Check all output ports
                    foreach (Siccity.XNode.NodePort output in node.Outputs)
                    {
                        //Check if port rect is available
                        if (!portConnectionPoints.ContainsKey(output))
                        {
                            continue;
                        }
                        Rect r = GridToWindowRect(portConnectionPoints[output]);
                        if (r.Contains(mousePos))
                        {
                            hoveredPort = output;
                        }
                    }
                }

                GUILayout.EndArea();
            }

            if (e.type != EventType.Layout && currentActivity == NodeActivity.DragGrid)
            {
                Selection.objects = preSelection.ToArray();
            }
            EndZoomed(position, zoom);

            //If a change in hash is detected in the selected node, call OnValidate method.
            //This is done through reflection because OnValidate is only relevant in editor,
            //and thus, the code should not be included in build.
            if (nodeHash != 0)
            {
                if (onValidate != null && nodeHash != Selection.activeObject.GetHashCode())
                {
                    onValidate.Invoke(Selection.activeObject, null);
                }
            }
        }
Beispiel #10
0
        public void Controls() {
            wantsMouseMove = true;
            Event e = Event.current;
            switch (e.type) {
                case EventType.MouseMove:
                    break;
                case EventType.ScrollWheel:
                    if (e.delta.y > 0) zoom += 0.1f * zoom;
                    else zoom -= 0.1f * zoom;
                    break;
                case EventType.MouseDrag:
                    if (e.button == 0) {
                        if (IsDraggingPort) {
                            if (IsHoveringPort && hoveredPort.IsInput) {
                                if (!draggedOutput.IsConnectedTo(hoveredPort)) {
                                    draggedOutputTarget = hoveredPort;
                                }
                            } else {
                                draggedOutputTarget = null;
                            }
                            Repaint();
                        } else if (currentActivity == NodeActivity.HoldHeader || currentActivity == NodeActivity.DragHeader) {
                            for (int i = 0; i < Selection.objects.Length; i++) {
                                if (Selection.objects[i] is Siccity.XNode.Node) {
                                    Siccity.XNode.Node node = Selection.objects[i] as Siccity.XNode.Node;
                                    node.position = WindowToGridPosition(e.mousePosition) + dragOffset[i];
                                    bool gridSnap = NodeEditorPreferences.GetSettings().gridSnap;
                                    if (e.control) {
                                        gridSnap = !gridSnap;
                                    }
                                    if (gridSnap) {
                                        node.position.x = (Mathf.Round((node.position.x + 8) / 16) * 16) - 8;
                                        node.position.y = (Mathf.Round((node.position.y + 8) / 16) * 16) - 8;
                                    }
                                }
                            }
                            currentActivity = NodeActivity.DragHeader;
                            Repaint();
                        } else if (currentActivity == NodeActivity.HoldGrid) {
                            currentActivity = NodeActivity.DragGrid;
                            preBoxSelection = Selection.objects;
                            dragBoxStart = WindowToGridPosition(e.mousePosition);
                            Repaint();
                        } else if (currentActivity == NodeActivity.DragGrid) {
                            foreach (Siccity.XNode.Node node in graph.nodes) {

                            }
                            Repaint();
                        }
                    } else if (e.button == 1 || e.button == 2) {
                        Vector2 tempOffset = panOffset;
                        tempOffset += e.delta * zoom;
                        // Round value to increase crispyness of UI text
                        tempOffset.x = Mathf.Round(tempOffset.x);
                        tempOffset.y = Mathf.Round(tempOffset.y);
                        panOffset = tempOffset;
                        isPanning = true;
                    }
                    break;
                case EventType.MouseDown:
                    Repaint();
                    if (e.button == 0) {

                        if (IsHoveringPort) {
                            if (hoveredPort.IsOutput) {
                                draggedOutput = hoveredPort;
                            } else {
                                hoveredPort.VerifyConnections();
                                if (hoveredPort.IsConnected) {
                                    Siccity.XNode.Node node = hoveredPort.node;
                                    Siccity.XNode.NodePort output = hoveredPort.Connection;
                                    hoveredPort.Disconnect(output);
                                    draggedOutput = output;
                                    draggedOutputTarget = hoveredPort;
                                    if (NodeEditor.onUpdateNode != null) NodeEditor.onUpdateNode(node);
                                }
                            }
                        } else if (IsHoveringNode && IsHoveringTitle(hoveredNode)) {
                            // If mousedown on node header, select or deselect
                            if (!Selection.Contains(hoveredNode)) SelectNode(hoveredNode, e.control || e.shift);
                            else if (e.control || e.shift) DeselectNode(hoveredNode);
                            e.Use();
                            currentActivity = NodeActivity.HoldHeader;
                            dragOffset = new Vector2[Selection.objects.Length];
                            for (int i = 0; i < dragOffset.Length; i++) {
                                if (Selection.objects[i] is Siccity.XNode.Node) {
                                    Siccity.XNode.Node node = Selection.objects[i] as Siccity.XNode.Node;
                                    dragOffset[i] = node.position - WindowToGridPosition(e.mousePosition);
                                }
                            }
                        }
                        // If mousedown on grid background, deselect all
                        else if (!IsHoveringNode) {
                            currentActivity = NodeActivity.HoldGrid;
                            if (!e.control && !e.shift) Selection.activeObject = null;
                        }
                    }
                    break;
                case EventType.MouseUp:
                    if (e.button == 0) {
                        //Port drag release
                        if (IsDraggingPort) {
                            //If connection is valid, save it
                            if (draggedOutputTarget != null) {
                                Siccity.XNode.Node node = draggedOutputTarget.node;
                                if (graph.nodes.Count != 0) draggedOutput.Connect(draggedOutputTarget);
                                if (NodeEditor.onUpdateNode != null) NodeEditor.onUpdateNode(node);
                                EditorUtility.SetDirty(graph);
                            }
                            //Release dragged connection
                            draggedOutput = null;
                            draggedOutputTarget = null;
                            EditorUtility.SetDirty(graph);
                            AssetDatabase.SaveAssets();
                        } else if (currentActivity == NodeActivity.DragHeader) {
                            AssetDatabase.SaveAssets();
                        } else if (!IsHoveringNode) {
                            // If click outside node, release field focus
                            if (!isPanning) {
                                GUIUtility.hotControl = 0;
                                GUIUtility.keyboardControl = 0;
                            }
                            AssetDatabase.SaveAssets();
                        }

                        // If click node header, select single node.
                        if (currentActivity == NodeActivity.HoldHeader && !(e.control || e.shift)) {
                            SelectNode(hoveredNode, false);
                        }

                        Repaint();
                        currentActivity = NodeActivity.Idle;
                    } else if (e.button == 1) {
                        if (!isPanning) {
                            if (IsHoveringNode && IsHoveringTitle(hoveredNode)) {
                                if (!Selection.Contains(hoveredNode)) SelectNode(hoveredNode, false);
                                ShowNodeContextMenu();
                            } else if (!IsHoveringNode) {
                                ShowGraphContextMenu();
                            }
                        }
                        isPanning = false;
                    }
                    break;
                case EventType.ValidateCommand:
                    if (e.commandName == "SoftDelete") RemoveSelectedNodes();
                    else if (e.commandName == "Duplicate") DublicateSelectedNodes();
                    Repaint();
                    break;
                case EventType.Ignore:
                    // If release mouse outside window
                    if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) {
                        Repaint();
                        currentActivity = NodeActivity.Idle;
                    }
                    break;
            }
        }
Beispiel #11
0
 public void CreateNode(Type type, Vector2 position) {
     Siccity.XNode.Node node = graph.AddNode(type);
     node.position = position;
     Repaint();
 }