| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 | using System;using System.Collections.Generic;using System.Linq;using UnityEditor;using UnityEngine;namespace XNodeEditor{    /// <summary> Base class to derive custom Node Graph editors from. Use this to override how graphs are drawn in the editor. </summary>    [CustomNodeGraphEditor(typeof(XNode.NodeGraph))]    public class NodeGraphEditor : XNodeEditor.Internal.NodeEditorBase<NodeGraphEditor, NodeGraphEditor.CustomNodeGraphEditorAttribute, XNode.NodeGraph>    {        [Obsolete("Use window.position instead")]        public Rect position        {            get { return window.position; }            set { window.position = value; }        }        /// <summary> Are we currently renaming a node? </summary>        protected bool isRenaming;        public virtual void OnGUI()        {        }        public virtual void OnGUI(UnityEngine.Object selectionCache)        {        }        /// <summary> Called when opened by NodeEditorWindow </summary>        public virtual void OnOpen()        {        }        public virtual void OnDisable()        {        }        /// <summary> Called when NodeEditorWindow gains focus </summary>        public virtual void OnWindowFocus()        {        }        /// <summary> Called when NodeEditorWindow loses focus </summary>        public virtual void OnWindowFocusLost()        {        }        public virtual Texture2D GetGridTexture()        {            return NodeEditorPreferences.GetSettings().gridTexture;        }        public virtual Texture2D GetSecondaryGridTexture()        {            return NodeEditorPreferences.GetSettings().crossTexture;        }        /// <summary> Return default settings for this graph type. This is the settings the user will load if no previous settings have been saved. </summary>        public virtual NodeEditorPreferences.Settings GetDefaultPreferences()        {            return new NodeEditorPreferences.Settings();        }        /// <summary> Returns context node menu path. Null or empty strings for hidden nodes. </summary>        public virtual string GetNodeMenuName(Type type)        {            //Check if type has the CreateNodeMenuAttribute            XNode.Node.CreateNodeMenuAttribute attrib;            if (NodeEditorUtilities.GetAttrib(type, out attrib)) // Return custom path                return attrib.menuName;            else // Return generated path                return NodeEditorUtilities.NodeDefaultPath(type);        }        /// <summary> The order by which the menu items are displayed. </summary>        public virtual int GetNodeMenuOrder(Type type)        {            //Check if type has the CreateNodeMenuAttribute            XNode.Node.CreateNodeMenuAttribute attrib;            if (NodeEditorUtilities.GetAttrib(type, out attrib)) // Return custom path                return attrib.order;            else                return 0;        }        /// <summary>        /// 这个方法是新增的,用于在创建的时候给节点自动改ShowName        /// </summary>        /// <param name="type"></param>        /// <returns></returns>        public virtual string GetShowName(Type type)        {            //Check if type has the CreateNodeMenuAttribute            XNode.Node.CreateNodeMenuAttribute attrib;            if (NodeEditorUtilities.GetAttrib(type, out attrib)) // Return custom path            {                if (attrib.showName != "")                    return attrib.showName;                else                    return NodeEditorUtilities.NodeDefaultPath(type);            }            else // Return generated path                return NodeEditorUtilities.NodeDefaultPath(type);        }        /// <summary> Add items for the context menu when right-clicking this node. Override to add custom menu items. </summary>        public virtual void AddContextMenuItems(GenericMenu menu)        {            Vector2 pos = NodeEditorWindow.current.WindowToGridPosition(Event.current.mousePosition);            var nodeTypes = NodeEditorReflection.nodeTypes.OrderBy(type => GetNodeMenuOrder(type)).ToArray();            for (int i = 0; i < nodeTypes.Length; i++)            {                Type type = nodeTypes[i];                //Get node context menu path                string path = GetNodeMenuName(type);                if (string.IsNullOrEmpty(path)) continue;                // Check if user is allowed to add more of given node type                XNode.Node.DisallowMultipleNodesAttribute disallowAttrib;                bool disallowed = false;                if (NodeEditorUtilities.GetAttrib(type, out disallowAttrib))                {                    int typeCount = target.nodes.Count(x => x.GetType() == type);                    if (typeCount >= disallowAttrib.max) disallowed = true;                }                // Add node entry to context menu                if (disallowed) menu.AddItem(new GUIContent(path), false, null);                else                    menu.AddItem(new GUIContent(path), false, () =>                    {                        XNode.Node node = CreateNode(type, pos);                        NodeEditorWindow.current.AutoConnect(node);                    });            }            menu.AddSeparator("");            if (NodeEditorWindow.copyBuffer != null && NodeEditorWindow.copyBuffer.Length > 0) menu.AddItem(new GUIContent("Paste"), false, () => NodeEditorWindow.current.PasteNodes(pos));            else menu.AddDisabledItem(new GUIContent("Paste"));            menu.AddItem(new GUIContent("Preferences"), false, () => NodeEditorReflection.OpenPreferences());            menu.AddCustomContextMenuItems(target);        }        /// <summary> Returned gradient is used to color noodles </summary>        /// <param name="output"> The output this noodle comes from. Never null. </param>        /// <param name="input"> The output this noodle comes from. Can be null if we are dragging the noodle. </param>        public virtual Gradient GetNoodleGradient(XNode.NodePort output, XNode.NodePort input)        {            Gradient grad = new Gradient();            // If dragging the noodle, draw solid, slightly transparent            if (input == null)            {                Color a = GetTypeColor(output.ValueType);                grad.SetKeys(                    new GradientColorKey[] {new GradientColorKey(a, 0f)},                    new GradientAlphaKey[] {new GradientAlphaKey(0.6f, 0f)}                );            }            // If normal, draw gradient fading from one input color to the other            else            {                Color a = GetTypeColor(output.ValueType);                Color b = GetTypeColor(input.ValueType);                // If any port is hovered, tint white                if (window.hoveredPort == output || window.hoveredPort == input)                {                    a = Color.Lerp(a, Color.white, 0.8f);                    b = Color.Lerp(b, Color.white, 0.8f);                }                grad.SetKeys(                    new GradientColorKey[] {new GradientColorKey(a, 0f), new GradientColorKey(b, 1f)},                    new GradientAlphaKey[] {new GradientAlphaKey(1f, 0f), new GradientAlphaKey(1f, 1f)}                );            }            return grad;        }        /// <summary> Returned float is used for noodle thickness </summary>        /// <param name="output"> The output this noodle comes from. Never null. </param>        /// <param name="input"> The output this noodle comes from. Can be null if we are dragging the noodle. </param>        public virtual float GetNoodleThickness(XNode.NodePort output, XNode.NodePort input)        {            return 5f;        }        public virtual NoodlePath GetNoodlePath(XNode.NodePort output, XNode.NodePort input)        {            return NodeEditorPreferences.GetSettings().noodlePath;        }        public virtual NoodleStroke GetNoodleStroke(XNode.NodePort output, XNode.NodePort input)        {            return NodeEditorPreferences.GetSettings().noodleStroke;        }        /// <summary> Returned color is used to color ports </summary>        public virtual Color GetPortColor(XNode.NodePort port)        {            return GetTypeColor(port.ValueType);        }        /// <summary> Returns generated color for a type. This color is editable in preferences </summary>        public virtual Color GetTypeColor(Type type)        {            return NodeEditorPreferences.GetTypeColor(type);        }        /// <summary> Override to display custom tooltip </summary>        public virtual string GetPortTooltip(XNode.NodePort port)        {            Type portType = port.ValueType;            string tooltip = "";            tooltip = portType.PrettyName();            if (port.IsOutput)            {                object obj = port.node.GetValue(port);                tooltip += " = " + (obj != null ? obj.ToString() : "null");            }            return tooltip;        }        /// <summary> Deal with objects dropped into the graph through DragAndDrop </summary>        public virtual void OnDropObjects(UnityEngine.Object[] objects)        {            if (GetType() != typeof(NodeGraphEditor)) Debug.Log("No OnDropObjects override defined for " + GetType());        }        /// <summary> Create a node and save it in the graph asset </summary>        public virtual XNode.Node CreateNode(Type type, Vector2 position)        {            Undo.RecordObject(target, "Create Node");            XNode.Node node = target.AddNode(type);            Undo.RegisterCreatedObjectUndo(node, "Create Node");            node.position = position;            node.name = GetShowName(type);            if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(target))) AssetDatabase.AddObjectToAsset(node, target);            if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();            NodeEditorWindow.RepaintAll();            return node;        }        /// <summary> Creates a copy of the original node in the graph </summary>        public virtual XNode.Node CopyNode(XNode.Node original)        {            Undo.RecordObject(target, "Duplicate Node");            XNode.Node node = target.CopyNode(original);            SetNodeIndex(node);            Undo.RegisterCreatedObjectUndo(node, "Duplicate Node");            node.name = original.name;            AssetDatabase.AddObjectToAsset(node, target);            if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();            return node;        }        protected virtual void SetNodeIndex(XNode.Node node)        {        }        /// <summary> Return false for nodes that can't be removed </summary>        public virtual bool CanRemove(XNode.Node node)        {            // Check graph attributes to see if this node is required            Type graphType = target.GetType();            XNode.NodeGraph.RequireNodeAttribute[] attribs = Array.ConvertAll(                graphType.GetCustomAttributes(typeof(XNode.NodeGraph.RequireNodeAttribute), true), x => x as XNode.NodeGraph.RequireNodeAttribute);            if (attribs.Any(x => x.Requires(node.GetType())))            {                if (target.nodes.Count(x => x.GetType() == node.GetType()) <= 1)                {                    return false;                }            }            return true;        }        /// <summary> Safely remove a node and all its connections. </summary>        public virtual void RemoveNode(XNode.Node node)        {            if (!CanRemove(node)) return;            // Remove the node            Undo.RecordObject(node, "Delete Node");            Undo.RecordObject(target, "Delete Node");            foreach (var port in node.Ports)            foreach (var conn in port.GetConnections())                Undo.RecordObject(conn.node, "Delete Node");            target.RemoveNode(node);            Undo.DestroyObjectImmediate(node);            if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets();        }        [AttributeUsage(AttributeTargets.Class)]        public class CustomNodeGraphEditorAttribute : Attribute,            XNodeEditor.Internal.NodeEditorBase<NodeGraphEditor, NodeGraphEditor.CustomNodeGraphEditorAttribute, XNode.NodeGraph>.INodeEditorAttrib        {            private Type inspectedType;            public string editorPrefsKey;            /// <summary> Tells a NodeGraphEditor which Graph type it is an editor for </summary>            /// <param name="inspectedType">Type that this editor can edit</param>            /// <param name="editorPrefsKey">Define unique key for unique layout settings instance</param>            public CustomNodeGraphEditorAttribute(Type inspectedType, string editorPrefsKey = "xNode.Settings")            {                this.inspectedType = inspectedType;                this.editorPrefsKey = editorPrefsKey;            }            public Type GetInspectedType()            {                return inspectedType;            }        }    }}
 |