Ejemplo n.º 1
0
        public void Controls()
        {
            wantsMouseMove = true;
            Event e = Event.current;

            switch (e.type)
            {
            case EventType.MouseMove:
                break;

            case EventType.ScrollWheel:
                float oldZoom = zoom;
                if (e.delta.y > 0)
                {
                    zoom += 0.1f * zoom;
                }
                else
                {
                    zoom -= 0.1f * zoom;
                }
                if (NodeEditorPreferences.GetSettings().zoomToMouse)
                {
                    panOffset += (1 - oldZoom / zoom) * (WindowToGridPosition(e.mousePosition) + panOffset);
                }
                break;

            case EventType.MouseDrag:
                if (e.button == 0)
                {
                    if (IsDraggingPort)
                    {
                        if (IsHoveringPort && hoveredPort.IsInput && draggedOutput.CanConnectTo(hoveredPort))
                        {
                            if (!draggedOutput.IsConnectedTo(hoveredPort))
                            {
                                draggedOutputTarget = hoveredPort;
                            }
                        }
                        else
                        {
                            draggedOutputTarget = null;
                        }
                        Repaint();
                    }
                    else if (currentActivity == NodeActivity.HoldNode)
                    {
                        RecalculateDragOffsets(e);
                        currentActivity = NodeActivity.DragNode;
                        Repaint();
                    }
                    if (currentActivity == NodeActivity.DragNode)
                    {
                        // Holding ctrl inverts grid snap
                        bool gridSnap = NodeEditorPreferences.GetSettings().gridSnap;
                        if (e.control)
                        {
                            gridSnap = !gridSnap;
                        }

                        Vector2 mousePos = WindowToGridPosition(e.mousePosition);
                        // Move selected nodes with offset
                        for (int i = 0; i < Selection.objects.Length; i++)
                        {
                            if (Selection.objects[i] is XNode.Node)
                            {
                                XNode.Node node    = Selection.objects[i] as XNode.Node;
                                Vector2    initial = node.position;
                                node.position = mousePos + dragOffset[i];
                                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;
                                }

                                // Offset portConnectionPoints instantly if a node is dragged so they aren't delayed by a frame.
                                Vector2 offset = node.position - initial;
                                if (offset.sqrMagnitude > 0)
                                {
                                    foreach (XNode.NodePort output in node.Outputs)
                                    {
                                        Rect rect;
                                        if (portConnectionPoints.TryGetValue(output, out rect))
                                        {
                                            rect.position += offset;
                                            portConnectionPoints[output] = rect;
                                        }
                                    }

                                    foreach (XNode.NodePort input in node.Inputs)
                                    {
                                        Rect rect;
                                        if (portConnectionPoints.TryGetValue(input, out rect))
                                        {
                                            rect.position += offset;
                                            portConnectionPoints[input] = rect;
                                        }
                                    }
                                }
                            }
                        }
                        // Move selected reroutes with offset
                        for (int i = 0; i < selectedReroutes.Count; i++)
                        {
                            Vector2 pos = mousePos + dragOffset[Selection.objects.Length + i];
                            if (gridSnap)
                            {
                                pos.x = (Mathf.Round(pos.x / 16) * 16);
                                pos.y = (Mathf.Round(pos.y / 16) * 16);
                            }
                            selectedReroutes[i].SetPoint(pos);
                        }
                        Repaint();
                    }
                    else if (currentActivity == NodeActivity.HoldGrid)
                    {
                        currentActivity        = NodeActivity.DragGrid;
                        preBoxSelection        = Selection.objects;
                        preBoxSelectionReroute = selectedReroutes.ToArray();
                        dragBoxStart           = WindowToGridPosition(e.mousePosition);
                        Repaint();
                    }
                    else if (currentActivity == NodeActivity.DragGrid)
                    {
                        Vector2 boxStartPos = GridToWindowPosition(dragBoxStart);
                        Vector2 boxSize     = e.mousePosition - boxStartPos;
                        if (boxSize.x < 0)
                        {
                            boxStartPos.x += boxSize.x; boxSize.x = Mathf.Abs(boxSize.x);
                        }
                        if (boxSize.y < 0)
                        {
                            boxStartPos.y += boxSize.y; boxSize.y = Mathf.Abs(boxSize.y);
                        }
                        selectionBox = new Rect(boxStartPos, boxSize);
                        Repaint();
                    }
                }
                else if (e.button == 1 || e.button == 2)
                {
                    panOffset += e.delta * zoom;
                    isPanning  = true;
                }
                break;

            case EventType.MouseDown:
                Repaint();
                if (e.button == 0)
                {
                    draggedOutputReroutes.Clear();

                    if (IsHoveringPort)
                    {
                        if (hoveredPort.IsOutput)
                        {
                            draggedOutput = hoveredPort;
                        }
                        else
                        {
                            hoveredPort.VerifyConnections();
                            if (hoveredPort.IsConnected)
                            {
                                XNode.Node     node   = hoveredPort.node;
                                XNode.NodePort output = hoveredPort.Connection;
                                int            outputConnectionIndex = output.GetConnectionIndex(hoveredPort);
                                draggedOutputReroutes = output.GetReroutePoints(outputConnectionIndex);
                                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);
                            if (!e.control && !e.shift)
                            {
                                selectedReroutes.Clear();
                            }
                        }
                        else if (e.control || e.shift)
                        {
                            DeselectNode(hoveredNode);
                        }

                        // Cache double click state, but only act on it in MouseUp - Except ClickCount only works in mouseDown.
                        isDoubleClick = (e.clickCount == 2);

                        e.Use();
                        currentActivity = NodeActivity.HoldNode;
                    }
                    else if (IsHoveringReroute)
                    {
                        // If reroute isn't selected
                        if (!selectedReroutes.Contains(hoveredReroute))
                        {
                            // Add it
                            if (e.control || e.shift)
                            {
                                selectedReroutes.Add(hoveredReroute);
                            }
                            // Select it
                            else
                            {
                                selectedReroutes = new List <RerouteReference>()
                                {
                                    hoveredReroute
                                };
                                Selection.activeObject = null;
                            }
                        }
                        // Deselect
                        else if (e.control || e.shift)
                        {
                            selectedReroutes.Remove(hoveredReroute);
                        }
                        e.Use();
                        currentActivity = NodeActivity.HoldNode;
                    }
                    // If mousedown on grid background, deselect all
                    else if (!IsHoveringNode)
                    {
                        currentActivity = NodeActivity.HoldGrid;
                        if (!e.control && !e.shift)
                        {
                            selectedReroutes.Clear();
                            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)
                        {
                            XNode.Node node = draggedOutputTarget.node;
                            if (graph.nodes.Count != 0)
                            {
                                draggedOutput.Connect(draggedOutputTarget);
                            }

                            // ConnectionIndex can be -1 if the connection is removed instantly after creation
                            int connectionIndex = draggedOutput.GetConnectionIndex(draggedOutputTarget);
                            if (connectionIndex != -1)
                            {
                                draggedOutput.GetReroutePoints(connectionIndex).AddRange(draggedOutputReroutes);
                                if (NodeEditor.onUpdateNode != null)
                                {
                                    NodeEditor.onUpdateNode(node);
                                }
                                EditorUtility.SetDirty(graph);
                            }
                        }
                        //Release dragged connection
                        draggedOutput       = null;
                        draggedOutputTarget = null;
                        EditorUtility.SetDirty(graph);
                        if (NodeEditorPreferences.GetSettings().autoSave)
                        {
                            AssetDatabase.SaveAssets();
                        }
                    }
                    else if (currentActivity == NodeActivity.DragNode)
                    {
                        IEnumerable <XNode.Node> nodes = Selection.objects.Where(x => x is XNode.Node).Select(x => x as XNode.Node);
                        foreach (XNode.Node node in nodes)
                        {
                            EditorUtility.SetDirty(node);
                        }
                        if (NodeEditorPreferences.GetSettings().autoSave)
                        {
                            AssetDatabase.SaveAssets();
                        }
                    }
                    else if (!IsHoveringNode)
                    {
                        // If click outside node, release field focus
                        if (!isPanning)
                        {
                            EditorGUI.FocusTextInControl(null);
                            EditorGUIUtility.editingTextField = false;
                        }
                        if (NodeEditorPreferences.GetSettings().autoSave)
                        {
                            AssetDatabase.SaveAssets();
                        }
                    }

                    // If click node header, select it.
                    if (currentActivity == NodeActivity.HoldNode && !(e.control || e.shift))
                    {
                        selectedReroutes.Clear();
                        SelectNode(hoveredNode, false);

                        // Double click to center node
                        if (isDoubleClick)
                        {
                            Vector2 nodeDimension = nodeSizes.ContainsKey(hoveredNode) ? nodeSizes[hoveredNode] / 2 : Vector2.zero;
                            panOffset = -hoveredNode.position - nodeDimension;
                        }
                    }

                    // If click reroute, select it.
                    if (IsHoveringReroute && !(e.control || e.shift))
                    {
                        selectedReroutes = new List <RerouteReference>()
                        {
                            hoveredReroute
                        };
                        Selection.activeObject = null;
                    }

                    Repaint();
                    currentActivity = NodeActivity.Idle;
                }
                else if (e.button == 1 || e.button == 2)
                {
                    if (!isPanning)
                    {
                        if (IsDraggingPort)
                        {
                            draggedOutputReroutes.Add(WindowToGridPosition(e.mousePosition));
                        }
                        else if (currentActivity == NodeActivity.DragNode && Selection.activeObject == null && selectedReroutes.Count == 1)
                        {
                            selectedReroutes[0].InsertPoint(selectedReroutes[0].GetPoint());
                            selectedReroutes[0] = new RerouteReference(selectedReroutes[0].port, selectedReroutes[0].connectionIndex, selectedReroutes[0].pointIndex + 1);
                        }
                        else if (IsHoveringReroute)
                        {
                            ShowRerouteContextMenu(hoveredReroute);
                        }
                        else if (IsHoveringPort)
                        {
                            ShowPortContextMenu(hoveredPort);
                        }
                        else if (IsHoveringNode && IsHoveringTitle(hoveredNode))
                        {
                            if (!Selection.Contains(hoveredNode))
                            {
                                SelectNode(hoveredNode, false);
                            }
                            GenericMenu menu = new GenericMenu();
                            NodeEditor.GetEditor(hoveredNode).AddContextMenuItems(menu);
                            menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero));
                            e.Use();     // Fixes copy/paste context menu appearing in Unity 5.6.6f2 - doesn't occur in 2018.3.2f1 Probably needs to be used in other places.
                        }
                        else if (!IsHoveringNode)
                        {
                            GenericMenu menu = new GenericMenu();
                            graphEditor.AddContextMenuItems(menu);
                            menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero));
                        }
                    }
                    isPanning = false;
                }
                // Reset DoubleClick
                isDoubleClick = false;
                break;

            case EventType.KeyDown:
                if (EditorGUIUtility.editingTextField)
                {
                    break;
                }
                else if (e.keyCode == KeyCode.F)
                {
                    Home();
                }
                if (IsMac())
                {
                    if (e.keyCode == KeyCode.Return)
                    {
                        RenameSelectedNode();
                    }
                }
                else
                {
                    if (e.keyCode == KeyCode.F2)
                    {
                        RenameSelectedNode();
                    }
                }
                break;

            case EventType.ValidateCommand:
            case EventType.ExecuteCommand:
                if (e.commandName == "SoftDelete")
                {
                    if (e.type == EventType.ExecuteCommand)
                    {
                        RemoveSelectedNodes();
                    }
                    e.Use();
                }
                else if (IsMac() && e.commandName == "Delete")
                {
                    if (e.type == EventType.ExecuteCommand)
                    {
                        RemoveSelectedNodes();
                    }
                    e.Use();
                }
                else if (e.commandName == "Duplicate")
                {
                    if (e.type == EventType.ExecuteCommand)
                    {
                        DuplicateSelectedNodes();
                    }
                    e.Use();
                }
                Repaint();
                break;

            case EventType.Ignore:
                // If release mouse outside window
                if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid)
                {
                    Repaint();
                    currentActivity = NodeActivity.Idle;
                }
                break;
            }
        }
Ejemplo n.º 2
0
        /// <summary> Update static ports and dynamic ports managed by DynamicPortLists to reflect class fields. </summary>
        public static void UpdatePorts(Node node, Dictionary <string, NodePort> ports)
        {
            if (!Initialized)
            {
                BuildCache();
            }

            Dictionary <string, NodePort>         staticPorts  = new Dictionary <string, NodePort>();
            Dictionary <string, List <NodePort> > removedPorts = new Dictionary <string, List <NodePort> >();

            System.Type nodeType = node.GetType();

            Dictionary <string, string> formerlySerializedAs = null;

            if (formerlySerializedAsCache != null)
            {
                formerlySerializedAsCache.TryGetValue(nodeType, out formerlySerializedAs);
            }

            List <NodePort> dynamicListPorts = new List <NodePort>();

            List <NodePort> typePortCache;

            if (portDataCache.TryGetValue(nodeType, out typePortCache))
            {
                for (int i = 0; i < typePortCache.Count; i++)
                {
                    staticPorts.Add(typePortCache[i].fieldName, portDataCache[nodeType][i]);
                }
            }

            // Cleanup port dict - Remove nonexisting static ports - update static port types
            // AND update dynamic ports (albeit only those in lists) too, in order to enforce proper serialisation.
            // Loop through current node ports
            foreach (NodePort port in ports.Values.ToList())
            {
                // If port still exists, check it it has been changed
                NodePort staticPort;
                if (staticPorts.TryGetValue(port.fieldName, out staticPort))
                {
                    // If port exists but with wrong settings, remove it. Re-add it later.
                    if (port.IsDynamic || port.direction != staticPort.direction || port.connectionType != staticPort.connectionType || port.typeConstraint != staticPort.typeConstraint)
                    {
                        // If port is not dynamic and direction hasn't changed, add it to the list so we can try reconnecting the ports connections.
                        if (!port.IsDynamic && port.direction == staticPort.direction)
                        {
                            removedPorts.Add(port.fieldName, port.GetConnections());
                        }
                        port.ClearConnections();
                        ports.Remove(port.fieldName);
                    }
                    else
                    {
                        port.ValueType = staticPort.ValueType;
                    }
                }
                // If port doesn't exist anymore, remove it
                else if (port.IsStatic)
                {
                    //See if the field is tagged with FormerlySerializedAs, if so add the port with its new field name to removedPorts
                    // so it can be reconnected in missing ports stage.
                    string newName = null;
                    if (formerlySerializedAs != null && formerlySerializedAs.TryGetValue(port.fieldName, out newName))
                    {
                        removedPorts.Add(newName, port.GetConnections());
                    }

                    port.ClearConnections();
                    ports.Remove(port.fieldName);
                }
                // If the port is dynamic and is managed by a dynamic port list, flag it for reference updates
                else if (IsDynamicListPort(port))
                {
                    dynamicListPorts.Add(port);
                }
            }
            // Add missing ports
            foreach (NodePort staticPort in staticPorts.Values)
            {
                if (!ports.ContainsKey(staticPort.fieldName))
                {
                    NodePort port = new NodePort(staticPort, node);
                    //If we just removed the port, try re-adding the connections
                    List <NodePort> reconnectConnections;
                    if (removedPorts.TryGetValue(staticPort.fieldName, out reconnectConnections))
                    {
                        for (int i = 0; i < reconnectConnections.Count; i++)
                        {
                            NodePort connection = reconnectConnections[i];
                            if (connection == null)
                            {
                                continue;
                            }
                            if (port.CanConnectTo(connection))
                            {
                                port.Connect(connection);
                            }
                        }
                    }
                    ports.Add(staticPort.fieldName, port);
                }
            }

            // Finally, make sure dynamic list port settings correspond to the settings of their "backing port"
            foreach (NodePort listPort in dynamicListPorts)
            {
                // At this point we know that ports here are dynamic list ports
                // which have passed name/"backing port" checks, ergo we can proceed more safely.
                string   backingPortName = listPort.fieldName.Split(' ')[0];
                NodePort backingPort     = staticPorts[backingPortName];

                // Update port constraints. Creating a new port instead will break the editor, mandating the need for setters.
                listPort.ValueType      = GetBackingValueType(backingPort.ValueType);
                listPort.direction      = backingPort.direction;
                listPort.connectionType = backingPort.connectionType;
                listPort.typeConstraint = backingPort.typeConstraint;
            }
        }
Ejemplo n.º 3
0
        /// <summary> Update static ports to reflect class fields. </summary>
        public static void UpdatePorts(Node node, Dictionary <string, NodePort> ports)
        {
            if (!Initialized)
            {
                BuildCache();
            }

            Dictionary <string, NodePort>         staticPorts  = new Dictionary <string, NodePort>();
            Dictionary <string, List <NodePort> > removedPorts = new Dictionary <string, List <NodePort> >();

            System.Type nodeType = node.GetType();

            List <NodePort> typePortCache;

            if (portDataCache.TryGetValue(nodeType, out typePortCache))
            {
                for (int i = 0; i < typePortCache.Count; i++)
                {
                    staticPorts.Add(typePortCache[i].fieldName, portDataCache[nodeType][i]);
                }
            }

            // Cleanup port dict - Remove nonexisting static ports - update static port types
            // Loop through current node ports
            foreach (NodePort port in ports.Values.ToList())
            {
                // If port still exists, check it it has been changed
                NodePort staticPort;
                if (staticPorts.TryGetValue(port.fieldName, out staticPort))
                {
                    // If port exists but with wrong settings, remove it. Re-add it later.
                    if (port.IsDynamic || port.direction != staticPort.direction || port.connectionType != staticPort.connectionType || port.typeConstraint != staticPort.typeConstraint)
                    {
                        // If port is not dynamic and direction hasn't changed, add it to the list so we can try reconnecting the ports connections.
                        if (!port.IsDynamic && port.direction == staticPort.direction)
                        {
                            removedPorts.Add(port.fieldName, port.GetConnections());
                        }
                        port.ClearConnections();
                        ports.Remove(port.fieldName);
                    }
                    else
                    {
                        port.ValueType = staticPort.ValueType;
                    }
                }
                // If port doesn't exist anymore, remove it
                else if (port.IsStatic)
                {
                    port.ClearConnections();
                    ports.Remove(port.fieldName);
                }
            }
            // Add missing ports
            foreach (NodePort staticPort in staticPorts.Values)
            {
                if (!ports.ContainsKey(staticPort.fieldName))
                {
                    NodePort port = new NodePort(staticPort, node);
                    //If we just removed the port, try re-adding the connections
                    List <NodePort> reconnectConnections;
                    if (removedPorts.TryGetValue(staticPort.fieldName, out reconnectConnections))
                    {
                        for (int i = 0; i < reconnectConnections.Count; i++)
                        {
                            NodePort connection = reconnectConnections[i];
                            if (connection == null)
                            {
                                continue;
                            }
                            if (port.CanConnectTo(connection))
                            {
                                port.Connect(connection);
                            }
                        }
                    }
                    ports.Add(staticPort.fieldName, port);
                }
            }
        }