コード例 #1
0
        private static void HandleGroupDragging(NodeEditorInputInfo inputInfo)
        {
            NodeEditorState state  = inputInfo.editorState;
            NodeGroup       active = state.activeGroup;

            if (active != null)
            {
                // Handle dragging and resizing of active group
                if (state.dragUserID != "group")
                {
                    state.activeGroup = null;
                    state.resizeGroup = false;
                    return;
                }

                // Update drag operation
                Vector2 dragChange = state.UpdateDrag("group", inputInfo.inputPos);
                Vector2 newSizePos = state.dragObjectPos;
                if (state.resizeGroup)
                {
                    // Resizing -> Apply drag to selected borders while keeping a minimum size
                    // Note: Binary operator and !=0 checks of the flag is enabled, but not necessarily the only flag (in which case you would use ==)
                    Rect r = active.rect;
                    if ((NodeGroup.resizeDir & BorderSelection.Left) != 0)
                    {
                        active.rect.xMin = r.xMax - Math.Max(minGroupSize, r.xMax - newSizePos.x);
                    }
                    else if ((NodeGroup.resizeDir & BorderSelection.Right) != 0)
                    {
                        active.rect.xMax = r.xMin + Math.Max(minGroupSize, newSizePos.x - r.xMin);
                    }

                    if ((NodeGroup.resizeDir & BorderSelection.Top) != 0)
                    {
                        active.rect.yMin = r.yMax - Math.Max(minGroupSize, r.yMax - newSizePos.y);
                    }
                    else if ((NodeGroup.resizeDir & BorderSelection.Bottom) != 0)
                    {
                        active.rect.yMax = r.yMin + Math.Max(minGroupSize, newSizePos.y - r.yMin);
                    }
                }
                else
                {
                    // Dragging -> Apply drag to body and pinned nodes
                    active.rect.position = newSizePos;
                    foreach (Node pinnedNode in active.pinnedNodes)
                    {
                        pinnedNode.position += dragChange;
                    }
                    foreach (NodeGroup pinnedGroup in active.pinnedGroups)
                    {
                        pinnedGroup.rect.position += dragChange;
                    }
                }

                inputInfo.inputEvent.Use();
                NodeEditor.RepaintClients();
            }
        }
コード例 #2
0
                               104)] // Priority over hundred to make it call after the GUI, and before Node dragging (110) and window panning (105)
        private static void HandleGroupDraggingStart(NodeEditorInputInfo inputInfo)
        {
            if (GUIUtility.hotControl > 0)
            {
                return; // GUI has control
            }
            NodeEditorState state = inputInfo.editorState;

            if (inputInfo.inputEvent.button == 0 && state.focusedNode == null && state.dragNode == false)
            {
                // Do not interfere with other dragging stuff
                NodeGroup focusedGroup = GroupAtPositionInput(state, NodeEditor.ScreenToCanvasSpace(inputInfo.inputPos));
                if (focusedGroup != null)
                {
                    // Start dragging the focused group
                    UpdateGroupOrder();
                    Vector2 canvasInputPos = NodeEditor.ScreenToCanvasSpace(inputInfo.inputPos);
                    if (CheckBorderSelection(state, focusedGroup.bodyRect, canvasInputPos, out NodeGroup.resizeDir))
                    {
                        // Resizing
                        state.activeGroup = focusedGroup;
                        // Get start drag position
                        Vector2 startSizePos = Vector2.zero;
                        if ((NodeGroup.resizeDir & BorderSelection.Left) != 0)
                        {
                            startSizePos.x = focusedGroup.rect.xMin;
                        }
                        else if ((NodeGroup.resizeDir & BorderSelection.Right) != 0)
                        {
                            startSizePos.x = focusedGroup.rect.xMax;
                        }
                        if ((NodeGroup.resizeDir & BorderSelection.Top) != 0)
                        {
                            startSizePos.y = focusedGroup.rect.yMin;
                        }
                        else if ((NodeGroup.resizeDir & BorderSelection.Bottom) != 0)
                        {
                            startSizePos.y = focusedGroup.rect.yMax;
                        }
                        // Start the resize drag
                        state.StartDrag("group", inputInfo.inputPos, startSizePos);
                        state.resizeGroup = true;
                        inputInfo.inputEvent.Use();
                    }
                    else if (focusedGroup.headerRect.Contains(canvasInputPos))
                    {
                        // Dragging
                        state.activeGroup = focusedGroup;
                        state.StartDrag("group", inputInfo.inputPos, state.activeGroup.rect.position);
                        state.activeGroup.UpdatePins();
                        inputInfo.inputEvent.Use();
                    }
                }
            }
        }
コード例 #3
0
        [EventHandlerAttribute(EventType.MouseDown, -1)]          // Before the other context clicks because they won't account for groups
        private static void HandleGroupContextClick(NodeEditorInputInfo inputInfo)
        {
            NodeEditorState state = inputInfo.editorState;

            if (inputInfo.inputEvent.button == 1 && state.focusedNode == null)
            {             // Right-click NOT on a node
                NodeGroup focusedGroup = HeaderAtPosition(state, NodeEditor.ScreenToCanvasSpace(inputInfo.inputPos));
                if (focusedGroup != null)
                {                 // Context click for the group. This is static, not dynamic, because it would be useless
                    GenericMenu context = new GenericMenu();
                    context.AddItem(new GUIContent("Delete"), false, () => { NodeEditor.curNodeCanvas = state.canvas; focusedGroup.Delete(); });
                    context.ShowAsContext();
                    inputInfo.inputEvent.Use();
                }
            }
        }
コード例 #4
0
 /// <summary>
 /// Gets a NodeGroup under the mouse. If multiple groups are adressed, the group lowest in the pin hierarchy is returned.
 /// </summary>
 private static NodeGroup GroupAtPosition(NodeEditorState state, Vector2 canvasPos)
 {
     if (NodeEditorInputSystem.shouldIgnoreInput(state))
     {
         return(null);
     }
     for (int i = state.canvas.groups.Count - 1; i >= 0; i--)
     {
         NodeGroup group = state.canvas.groups[i];
         if (group.headerRect.Contains(canvasPos) || group.rect.Contains(canvasPos))
         {
             return(group);
         }
     }
     return(null);
 }
コード例 #5
0
        [EventHandlerAttribute(EventType.MouseDown, 20)] // Priority over hundred to make it call after the GUI
        private static void HandleWindowSelectionStart(NodeEditorInputInfo inputInfo)
        {
            if (GUIUtility.hotControl > 0)
            {
                return; // GUI has control
            }
            NodeEditorState state = inputInfo.editorState;

            if (inputInfo.inputEvent.button == 0 && state.focusedNode == null &&
                NodeGroup.HeaderAtPosition(state, NodeEditor.ScreenToCanvasSpace(inputInfo.inputPos)) == null)
            {
                // Left clicked on the empty canvas -> Start the selection process
                state.boxSelecting = true;
                startSelectionPos  = inputInfo.inputPos;
            }
        }
コード例 #6
0
        /// <summary>
        /// Gets a NodeGroup which has it's header under the mouse. If multiple groups are adressed, the smallest is returned.
        /// </summary>
        private static NodeGroup HeaderAtPosition(NodeEditorState state, Vector2 canvasPos)
        {
            if (NodeEditorInputSystem.shouldIgnoreInput(state))
            {
                return(null);
            }
            NodeCanvas canvas = state.canvas;

            for (int groupCnt = canvas.groups.Count - 1; groupCnt >= 0; groupCnt--)
            {
                NodeGroup group = canvas.groups[groupCnt];
                if (group.headerRect.Contains(canvasPos))
                {
                    return(group);
                }
            }
            return(null);
        }
コード例 #7
0
        /// <summary>
        /// Gets a NodeGroup under the mouse that requires input (header or border). If multiple groups are adressed, the group lowest in the pin hierarchy is returned.
        /// 获取鼠标点击的需要执行操作的Group(Header或Border),如果找到了多个group,则只处理第一个group
        /// </summary>
        private static NodeGroup GroupAtPositionInput(NodeEditorState state, Vector2 canvasPos)
        {
            if (NodeEditorInputSystem.shouldIgnoreInput(state))
            {
                return(null);
            }
            for (int i = state.canvas.groups.Count - 1; i >= 0; i--)
            {
                NodeGroup       group = state.canvas.groups[i];
                BorderSelection border;
                if (group.headerRect.Contains(canvasPos) || CheckBorderSelection(state, group.bodyRect, canvasPos, out border))
                {
                    return(group);
                }
            }

            return(null);
        }
コード例 #8
0
 /// <summary>
 /// Recursively adds the pinned nodes and subGroups to the active group's pinned nodes and groups
 /// </summary>
 private void AddPins()
 {
     for (int groupCnt = NodeEditor.curNodeCanvas.groups.IndexOf(this); groupCnt < NodeEditor.curNodeCanvas.groups.Count; groupCnt++)
     {             // Get all pinned groups -> all groups atleast half in the group
         NodeGroup group = NodeEditor.curNodeCanvas.groups[groupCnt];
         if (rect.Contains(group.rect.center) && group != this && !pinnedGroups.Contains(group))
         {
             pinnedGroups.Add(group);
             group.AddPins();
         }
     }
     foreach (Node node in NodeEditor.curNodeCanvas.nodes)
     {             // Get all pinned nodes -> all nodes atleast half in the group
         if (rect.Contains(node.rect.center) && !pinnedNodes.Contains(node))
         {
             pinnedNodes.Add(node);
         }
     }
 }
コード例 #9
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);
            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.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.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];
                if (Event.current.type == EventType.Layout)
                {
                    node.isClipped = !curEditorState.canvasViewport.Overlaps(curNodeCanvas.nodes[nodeCnt].fullAABBRect);
                }
                if (!node.isClipped)
                {
                    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();
        }
コード例 #10
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();
        }
コード例 #11
0
        /// <summary>
        /// Validates this canvas, checking for any broken nodes or references and cleans them.
        /// </summary>
        public void Validate(bool deepValidate = false)
        {
            if (nodes == null)
            {
                Debug.LogWarning("NodeCanvas '" + name + "' nodes were erased and set to null! Automatically fixed!");
                nodes = new List <Node> ();
            }
            if (deepValidate)
            {
                for (int groupCnt = 0; groupCnt < groups.Count; groupCnt++)
                {
                    NodeGroup group = groups[groupCnt];
                    if (group == null)
                    {
                        Debug.LogWarning("NodeCanvas '" + name + "' contained broken (null) group! Automatically fixed!");
                        groups.RemoveAt(groupCnt);
                        groupCnt--;
                        continue;
                    }
                }
                for (int nodeCnt = 0; nodeCnt < nodes.Count; nodeCnt++)
                {
                    Node node = nodes[nodeCnt];
                    if (node == null)
                    {
                        Debug.LogWarning("NodeCanvas '" + saveName + "' (" + name + ") contained broken (null) node! Automatically fixed!");
                        nodes.RemoveAt(nodeCnt);
                        nodeCnt--;
                        continue;
                    }
                    for (int knobCnt = 0; knobCnt < node.nodeKnobs.Count; knobCnt++)
                    {
                        NodeKnob nodeKnob = node.nodeKnobs[knobCnt];
                        if (nodeKnob == null)
                        {
                            Debug.LogWarning("NodeCanvas '" + name + "' Node '" + node.name + "' contained broken (null) NodeKnobs! Automatically fixed!");
                            nodes.RemoveAt(nodeCnt);
                            nodeCnt--;
                            break;
//							node.nodeKnobs.RemoveAt (knobCnt);
//							knobCnt--;
//							continue;
                        }

                        if (nodeKnob is NodeInput)
                        {
                            NodeInput input = nodeKnob as NodeInput;
                            if (input.connection != null && input.connection.body == null)
                            {                             // References broken node; Clear connection
                                input.connection = null;
                            }
                            //						for (int conCnt = 0; conCnt < (nodeKnob as NodeInput).connection.Count; conCnt++)
                        }
                        else if (nodeKnob is NodeOutput)
                        {
                            NodeOutput output = nodeKnob as NodeOutput;
                            for (int conCnt = 0; conCnt < output.connections.Count; conCnt++)
                            {
                                NodeInput con = output.connections[conCnt];
                                if (con == null || con.body == null)
                                {                                 // Broken connection; Clear connection
                                    output.connections.RemoveAt(conCnt);
                                    conCnt--;
                                }
                            }
                        }
                    }
                }
                if (editorStates == null)
                {
                    Debug.LogWarning("NodeCanvas '" + name + "' editorStates were erased! Automatically fixed!");
                    editorStates = new NodeEditorState[0];
                }
                editorStates = editorStates.Where((NodeEditorState state) => state != null).ToArray();
                foreach (NodeEditorState state in editorStates)
                {
                    if (!nodes.Contains(state.selectedNode))
                    {
                        state.selectedNode = null;
                    }
                }
            }
            OnValidate();
        }