diff --git a/Sample/Editor/HelloWorld.asset b/Sample/Editor/HelloEditor.asset similarity index 96% rename from Sample/Editor/HelloWorld.asset rename to Sample/Editor/HelloEditor.asset index 8dfc869..6cec36b 100644 --- a/Sample/Editor/HelloWorld.asset +++ b/Sample/Editor/HelloEditor.asset @@ -10,7 +10,7 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: cde084f079a7426daa86ed86cb80ed1b, type: 3} - m_Name: HelloWorld + m_Name: HelloEditor m_EditorClassIdentifier: nodeData: rid: -2 diff --git a/Sample/Editor/HelloWorld.asset.meta b/Sample/Editor/HelloEditor.asset.meta similarity index 79% rename from Sample/Editor/HelloWorld.asset.meta rename to Sample/Editor/HelloEditor.asset.meta index 0ec0efa..8e83052 100644 --- a/Sample/Editor/HelloWorld.asset.meta +++ b/Sample/Editor/HelloEditor.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ad64ccb31efdc9c4082380856cd58efc +guid: 0ecaf7effd4cb5545b03d4f552942c80 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Sample/Editor/HelloEditor.cs b/Sample/Editor/HelloEditor.cs new file mode 100644 index 0000000..84da187 --- /dev/null +++ b/Sample/Editor/HelloEditor.cs @@ -0,0 +1,22 @@ +using TNode.Editor; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEngine; + +namespace Sample.Editor{ + public class HelloEditor : GraphEditor{ + [OnOpenAsset] + public static bool OnOpenAsset(int instanceID, int line){ + var graph = EditorUtility.InstanceIDToObject(instanceID) as HelloGraph; + if (graph != null) + { + var wnd = GetWindow(); + wnd.titleContent = new GUIContent("HelloGraph Editor"); + wnd.CreateGUI(); + wnd._graphView.Data = graph; + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/Sample/Editor/HelloEditor.cs.meta b/Sample/Editor/HelloEditor.cs.meta new file mode 100644 index 0000000..f4006fa --- /dev/null +++ b/Sample/Editor/HelloEditor.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a5c15a07ff247a247a73d6991b540e27 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - m_ViewDataDictionary: {instanceID: 0} + - mVisualTreeAsset: {fileID: 9197481963319205126, guid: b67f6dcbe2361b649ad2b7845207321b, type: 3} + - nodeEditorData: {fileID: 11400000, guid: 0ecaf7effd4cb5545b03d4f552942c80, type: 2} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Sample/Editor/HelloGraph.cs b/Sample/Editor/HelloGraph.cs new file mode 100644 index 0000000..89b4857 --- /dev/null +++ b/Sample/Editor/HelloGraph.cs @@ -0,0 +1,11 @@ +using System; +using TNode.Models; +using UnityEngine; + +namespace Sample.Editor{ + [CreateAssetMenu(fileName = "New HelloGraph", menuName = "TNode/HelloGraph")] + [Serializable] + public class HelloGraph : GraphData{ + + } +} \ No newline at end of file diff --git a/Sample/Editor/HelloWorldGraph.cs.meta b/Sample/Editor/HelloGraph.cs.meta similarity index 83% rename from Sample/Editor/HelloWorldGraph.cs.meta rename to Sample/Editor/HelloGraph.cs.meta index 982b74d..f83e4e4 100644 --- a/Sample/Editor/HelloWorldGraph.cs.meta +++ b/Sample/Editor/HelloGraph.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8b641f4bc28454e4aa2c5ddc629b07c2 +guid: 9eda9b79596ecc746bb59fa8939c6ac3 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Sample/Editor/HelloGraphView.cs b/Sample/Editor/HelloGraphView.cs new file mode 100644 index 0000000..819917f --- /dev/null +++ b/Sample/Editor/HelloGraphView.cs @@ -0,0 +1,9 @@ +using TNode.Attribute; +using TNode.Editor.BaseViews; + +namespace Sample.Editor{ + [NodeComponent] + public class HelloGraphView : DataGraphView{ + + } +} \ No newline at end of file diff --git a/Sample/Editor/HelloWorld.cs.meta b/Sample/Editor/HelloGraphView.cs.meta similarity index 54% rename from Sample/Editor/HelloWorld.cs.meta rename to Sample/Editor/HelloGraphView.cs.meta index f68d71c..695c259 100644 --- a/Sample/Editor/HelloWorld.cs.meta +++ b/Sample/Editor/HelloGraphView.cs.meta @@ -1,10 +1,9 @@ fileFormatVersion: 2 -guid: 7b39119946f2f83458e3c2bafb200552 +guid: 8ec139b86ff8c10488c233a10e6106f4 MonoImporter: externalObjects: {} serializedVersion: 2 - defaultReferences: - - nodeEditorData: {fileID: 11400000, guid: ad64ccb31efdc9c4082380856cd58efc, type: 2} + defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: diff --git a/Sample/Editor/HelloWorld.cs b/Sample/Editor/HelloWorld.cs deleted file mode 100644 index 9de7b9e..0000000 --- a/Sample/Editor/HelloWorld.cs +++ /dev/null @@ -1,10 +0,0 @@ -using TNode.Editor; -using UnityEditor; -using UnityEditor.Callbacks; -using UnityEditor.Experimental.GraphView; -using UnityEngine; -using UnityEngine.UIElements; - -public class HelloWorld : GraphEditor{ - -} \ No newline at end of file diff --git a/Sample/Editor/HelloWorldGraph.cs b/Sample/Editor/HelloWorldGraph.cs deleted file mode 100644 index bc22163..0000000 --- a/Sample/Editor/HelloWorldGraph.cs +++ /dev/null @@ -1,4 +0,0 @@ -using TNode.Models; -public class HelloWorldGraph : GraphData{ - -} \ No newline at end of file diff --git a/Sample/New HelloGraph.asset b/Sample/New HelloGraph.asset new file mode 100644 index 0000000..51e5c37 --- /dev/null +++ b/Sample/New HelloGraph.asset @@ -0,0 +1,23 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9eda9b79596ecc746bb59fa8939c6ac3, type: 3} + m_Name: New HelloGraph + m_EditorClassIdentifier: + nodes: [] + nodeLinks: [] + entryNode: + rid: -2 + references: + version: 2 + RefIds: + - rid: -2 + type: {class: , ns: , asm: } diff --git a/Sample/New HelloGraph.asset.meta b/Sample/New HelloGraph.asset.meta new file mode 100644 index 0000000..9f50717 --- /dev/null +++ b/Sample/New HelloGraph.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: edfa4bd023c6a7641aec2257a5e1248e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TNode/Attribute/NodeAttribute.cs b/TNode/Attribute/NodeAttribute.cs new file mode 100644 index 0000000..f27663f --- /dev/null +++ b/TNode/Attribute/NodeAttribute.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; +using TNode.Models; + +namespace TNode.Attribute{ + [MeansImplicitUse] + [BaseTypeRequired(typeof(NodeData))] + + public class NodeAttribute:System.Attribute{ + public NodeAttribute(GraphData graphData){ + + } + } +} \ No newline at end of file diff --git a/TNode/Attribute/NodeAttribute.cs.meta b/TNode/Attribute/NodeAttribute.cs.meta new file mode 100644 index 0000000..2950fdf --- /dev/null +++ b/TNode/Attribute/NodeAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2311dd22c61449b7aa44b37085623fc4 +timeCreated: 1656298063 \ No newline at end of file diff --git a/TNode/Editor/BaseViews/DataGraphView.cs b/TNode/Editor/BaseViews/DataGraphView.cs index 1bd6d14..b0e3493 100644 --- a/TNode/Editor/BaseViews/DataGraphView.cs +++ b/TNode/Editor/BaseViews/DataGraphView.cs @@ -1,13 +1,110 @@ -using TNode.Cache; +using System; +using System.Collections.Generic; +using TNode.BaseViews; +using TNode.Cache; using TNode.Models; +using UnityEditor; using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.UIElements; -namespace TNode.BaseViews{ +namespace TNode.Editor.BaseViews{ + /* + public class DialogueGraphView : DataGraphView{ + public Action onNodeAdded; + public Action onNodeSelected; + public Action onNodeRemoved; + public Action onNodeUnselected; + // public DialogueGraphView(DialogueGraph graph):base(){ + // this.Data = graph; + // + // //Set background to a bit of darker + // + // + // //Register a data context change callback + // + // } + + public override void OnGraphViewCreate(){ + AddNode(GenerateEntryPoint()); + RegisterCallback(evt => { + var pos = evt.mousePosition; + + evt.menu.AppendAction("Add NodeAttribute", (dropMenuAction) => { + DialogueNodeView nodeView = new DialogueNodeView{ + GUID = Guid.NewGuid().ToString(), + title = "New NodeAttribute" + }; + // make it a 200x100 box + nodeView.SetPosition(new Rect(pos.x - 100, pos.y - 50, 200, 100)); + + + AddNode(nodeView); + }, DropdownMenuAction.AlwaysEnabled); + }); + this.OnDataChanged += OnOnDataChanged; + } + private void OnOnDataChanged(object sender, DataChangedEventArgs e){ + //clean all nodes from the graphview + foreach (var graphViewNode in nodes){ + RemoveElement(graphViewNode); + } + + foreach (var edge in edges){ + RemoveElement(edge); + } + //add all nodes from the new graph + foreach (var node in e.NewData.nodes){ + //AddNode(node); + } + } + + public void AddNode(DialogueNodeData dialogueNodeData){ + var res = InstantiateFromDialogueNodeData(dialogueNodeData); + AddNode(res); + } + public void AddNode(DialogueNodeView nodeView){ + AddElement(nodeView); + onNodeAdded?.Invoke(nodeView); + //Register nodeView selection callback + nodeView.RegisterCallback(evt => { + if (evt.clickCount == 1){ + onNodeSelected?.Invoke(nodeView); + } + }); + nodeView.OnUnselect += () => { onNodeUnselected?.Invoke(nodeView); }; + } + + public override List GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter) => this.ports.ToList() + .Where(x => x != startPort && + x.direction != startPort.direction).ToList(); + + public DialogueNodeView GenerateEntryPoint(){ + var entryPoint = new DialogueNodeView{ + title = "Entry Point", + GUID = Guid.NewGuid().ToString(), + EntryPoint = true + }; + //Add output port to the nodeView + entryPoint.AddPort(Orientation.Horizontal, Direction.Output, "Next"); + //Set nodeView position to top center side of screen + entryPoint.SetPosition(new Rect(this.layout.width / 2 - 100, 0, 200, 200)); + return entryPoint; + } + protected DialogueNodeView InstantiateFromDialogueNodeData(DialogueNodeData dialogueNodeData){ + var node = new DialogueNodeView(); + node.title = dialogueNodeData.nodeName; + node.GUID = Guid.NewGuid().ToString(); + //TODO:after completing the separation of the node data and the node editor data,this should be switch to the node editor data + //node.SetPosition(dialogueNodeData.rect); + this.AddNode(node); + return node; + } + } + */ public abstract class DataGraphView:GraphView where T:GraphData{ private T _data; - + private SearchWindowProvider _searchWindowProvider; public T Data{ get{ return _data; } set{ @@ -33,7 +130,7 @@ namespace TNode.BaseViews{ //Get the node type var nodeType = dataNode.GetType(); - //Get the derived type of Node View from the node type + //Get the derived type of NodeAttribute View from the node type var nodeViewType = typeof(NodeView<>).MakeGenericType(nodeType); //Fetch the node view from the node view type @@ -61,9 +158,23 @@ namespace TNode.BaseViews{ public event DataChangedEventHandler OnDataChanged; public delegate void DataChangedEventHandler(object sender, DataChangedEventArgs e); + + private void ConstructDefaultBehaviour(){ + //Register a right click context menu + //ConstructContextualMenuOption(); + } + + public void ConstructViewContextualMenu(EventCallback callback){ + RegisterCallback(callback); + } + private void OnInit(){ + ConstructDefaultBehaviour(); OnGraphViewCreate(); } + + + public virtual void OnGraphViewCreate(){ } @@ -73,6 +184,14 @@ namespace TNode.BaseViews{ ~DataGraphView(){ OnGraphViewDestroy(); } + //rewrite function of the derived class in the comment on the top of this script file in this class + // public abstract override List GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter); + // + // public void AddNode(NodeData nodeData){ + // + // } + + } public class DataChangedEventArgs{ diff --git a/TNode/Editor/BaseViews/NodeView.cs b/TNode/Editor/BaseViews/NodeView.cs index a2596f8..60777c4 100644 --- a/TNode/Editor/BaseViews/NodeView.cs +++ b/TNode/Editor/BaseViews/NodeView.cs @@ -4,7 +4,7 @@ using UnityEditor.Experimental.GraphView; namespace TNode.BaseViews{ - //A Node monitor some type of node in the graph + //A NodeAttribute monitor some type of node in the graph public abstract class NodeView : Node where T:NodeData,new(){ protected T _data; diff --git a/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs b/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs index 9402842..b81282b 100644 --- a/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs +++ b/TNode/Editor/BaseViews/SimpleGraphSubWindow.cs @@ -6,13 +6,13 @@ namespace TNode.BaseViews{ public class SimpleGraphSubWindow:GraphElement{ private readonly Dragger _dragger = new Dragger(); - private void ConstructWindowBasicSetting(){ + protected void ConstructWindowBasicSetting(){ RegisterCallback(evt => { evt.StopPropagation(); }); focusable = false; capabilities |= Capabilities.Movable | Capabilities.Resizable; this.AddManipulator(_dragger); } - private void BuildWindow(VisualTreeAsset visualTreeAsset){ + protected void BuildWindow(VisualTreeAsset visualTreeAsset){ if(visualTreeAsset != null){ visualTreeAsset.CloneTree(this); } diff --git a/TNode/Editor/Cache/NodeEditorExtensions.cs b/TNode/Editor/Cache/NodeEditorExtensions.cs index 7f507d9..4d8f57b 100644 --- a/TNode/Editor/Cache/NodeEditorExtensions.cs +++ b/TNode/Editor/Cache/NodeEditorExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using TNode.Attribute; using TNode.BaseViews; +using TNode.Editor.BaseViews; using UnityEngine; namespace TNode.Cache{ @@ -45,5 +46,9 @@ namespace TNode.Cache{ var instance = Activator.CreateInstance(implementedType); return instance; } + public static bool HasSpecificType() where T : class{ + var implementedType = NodeEditorSingleton.Instance.FromGenericToSpecific[typeof(T)] as T; + return (T)implementedType!=null; + } } } \ No newline at end of file diff --git a/TNode/Editor/GraphEditor.cs b/TNode/Editor/GraphEditor.cs index 38fd04c..24b0f55 100644 --- a/TNode/Editor/GraphEditor.cs +++ b/TNode/Editor/GraphEditor.cs @@ -1,9 +1,11 @@ using Codice.CM.Common; using TNode.BaseViews; using TNode.Cache; +using TNode.Editor.BaseViews; using TNode.Editor.Model; using TNode.Models; using UnityEditor; +using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.Serialization; using UnityEngine.UIElements; @@ -28,20 +30,35 @@ namespace TNode.Editor{ // Instantiate UXML VisualElement labelFromUXML = mVisualTreeAsset.Instantiate(); root.Add(labelFromUXML); - + BuildGraphView(); - - - DefineGraphEditorActions(); - - OnCreate(); } private void BuildGraphView(){ _graphView = NodeEditorExtensions.CreateInstance>(); rootVisualElement.Add(_graphView); _graphView.StretchToParentSize(); + + + _graphView.ConstructViewContextualMenu(evt => { + + //Current issue is that the search window don't show up at the exact position of the mouse click by dma.eventInfo.mousePosition + //So I have to manually set the position of the search window to fit the mouse click position by add an offset driven by Editor's position + //Maybe a better way exists to fix this issue + Vector2 editorPosition = this.position.position; + + + evt.menu.AppendAction("Create Node", dma => { + var dmaPos = dma.eventInfo.mousePosition+editorPosition; + SearchWindowContext searchWindowContext = new SearchWindowContext(dmaPos,200,200); + SearchWindow.Open(searchWindowContext, ScriptableObject.CreateInstance()); + }); + }); + } + private void ConstructSearchWindow(){ + //Register a search window + } private void DefineGraphEditorActions(){ diff --git a/TNode/Editor/GraphEditorData.cs b/TNode/Editor/GraphEditorData.cs index 8d17f52..20f999c 100644 --- a/TNode/Editor/GraphEditorData.cs +++ b/TNode/Editor/GraphEditorData.cs @@ -4,7 +4,7 @@ using UnityEngine; namespace TNode.Editor{ - [CreateAssetMenu(fileName = "Node Editor Config", menuName = "TNode/Node Editor Config")] + [CreateAssetMenu(fileName = "NodeAttribute Editor Config", menuName = "TNode/NodeAttribute Editor Config")] public class GraphEditorData:ScriptableObject{ public List nodesData; diff --git a/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs b/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs new file mode 100644 index 0000000..0bc873e --- /dev/null +++ b/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs @@ -0,0 +1,34 @@ +using System; +using TNode.Cache; +using TNode.Editor.Inspector.InspectorImplementation; +using UnityEditor; +using UnityEngine.UIElements; + +namespace TNode.Editor.Inspector{ + public class DefaultInspectorItemFactory{ + + public InspectorItem Create(){ + //Check type of T + var hasSpecificType = NodeEditorExtensions.HasSpecificType>(); + if (hasSpecificType){ + return NodeEditorExtensions.CreateInstance>(); + } + else{ + return DefaultInspectorItem(); + } + } + + public static InspectorItem DefaultInspectorItem(){ + DefaultInspectorItem item = new DefaultInspectorItem(); + if (typeof(string) == typeof(T)){ + item.foldOut.Add(new TextField(){ + name = "StringTextField" + }); + } + + return item; + + } + } +} + \ No newline at end of file diff --git a/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs.meta b/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs.meta new file mode 100644 index 0000000..f9838bb --- /dev/null +++ b/TNode/Editor/Inspector/DefaultInspectorItemFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 83b9e37f79cf4a18b265e3e22e7e3ced +timeCreated: 1656142463 \ No newline at end of file diff --git a/TNode/Editor/Inspector/INodeDataBinding.cs b/TNode/Editor/Inspector/INodeDataBinding.cs index 563de65..1fe044b 100644 --- a/TNode/Editor/Inspector/INodeDataBinding.cs +++ b/TNode/Editor/Inspector/INodeDataBinding.cs @@ -2,7 +2,7 @@ using UnityEngine; namespace TNode.Editor.Inspector{ - public interface INodeDataBinding{ + public interface INodeDataBinding:INodeDataBindingBase{ protected T GetValue(){ var fieldInfo = typeof(T).GetField(BindingPath, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); @@ -15,8 +15,11 @@ namespace TNode.Editor.Inspector{ } return default; } - public string BindingPath{ get; set; } - public NodeData BindingNodeData{ get; set; } + public T Value => GetValue(); + + public void OnBindingDataUpdate(){ + + } } } \ No newline at end of file diff --git a/TNode/Editor/Inspector/INodeDataBindingBase.cs b/TNode/Editor/Inspector/INodeDataBindingBase.cs new file mode 100644 index 0000000..bb367b9 --- /dev/null +++ b/TNode/Editor/Inspector/INodeDataBindingBase.cs @@ -0,0 +1,8 @@ +using TNode.Models; + +namespace TNode.Editor.Inspector{ + public interface INodeDataBindingBase{ + public string BindingPath{ get; set; } + public NodeData BindingNodeData{ get; set; } + } +} \ No newline at end of file diff --git a/TNode/Editor/Inspector/INodeDataBindingBase.cs.meta b/TNode/Editor/Inspector/INodeDataBindingBase.cs.meta new file mode 100644 index 0000000..7885931 --- /dev/null +++ b/TNode/Editor/Inspector/INodeDataBindingBase.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2445523267fc49d3a17639a5c3ee47c7 +timeCreated: 1656210915 \ No newline at end of file diff --git a/TNode/Editor/Inspector/InspectorImplementation.meta b/TNode/Editor/Inspector/InspectorImplementation.meta new file mode 100644 index 0000000..d8de6bd --- /dev/null +++ b/TNode/Editor/Inspector/InspectorImplementation.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4cdebd0430794d32918ba8c63d71d0cc +timeCreated: 1656142311 \ No newline at end of file diff --git a/TNode/Editor/Inspector/InspectorImplementation/DefaultInspectorItem.cs b/TNode/Editor/Inspector/InspectorImplementation/DefaultInspectorItem.cs new file mode 100644 index 0000000..2dd72c2 --- /dev/null +++ b/TNode/Editor/Inspector/InspectorImplementation/DefaultInspectorItem.cs @@ -0,0 +1,16 @@ +using UnityEngine.UIElements; + +namespace TNode.Editor.Inspector.InspectorImplementation{ + public class DefaultInspectorItem:InspectorItem{ + public readonly Foldout foldOut; + public DefaultInspectorItem(){ + foldOut = new Foldout{ + text = "" + }; + this.Add(foldOut); + OnValueChanged += () => { + foldOut.text = this.BindingPath; + }; + } + } +} \ No newline at end of file diff --git a/TNode/Editor/Inspector/InspectorImplementation/DefaultInspectorItem.cs.meta b/TNode/Editor/Inspector/InspectorImplementation/DefaultInspectorItem.cs.meta new file mode 100644 index 0000000..c837e6d --- /dev/null +++ b/TNode/Editor/Inspector/InspectorImplementation/DefaultInspectorItem.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6b4f88e6c094449280ba5e38cb508287 +timeCreated: 1656143219 \ No newline at end of file diff --git a/TNode/Editor/Inspector/InspectorItem.cs b/TNode/Editor/Inspector/InspectorItem.cs index a3c9077..09de53f 100644 --- a/TNode/Editor/Inspector/InspectorItem.cs +++ b/TNode/Editor/Inspector/InspectorItem.cs @@ -4,7 +4,41 @@ using UnityEngine.UIElements; namespace TNode.Editor.Inspector{ public abstract class InspectorItem:VisualElement,INodeDataBinding{ - public string BindingPath{ get; set; } - public NodeData BindingNodeData{ get; set; } + private NodeData _bindingNodeData; + private string _bindingFieldName; + protected event System.Action OnValueChanged; + + public string BindingPath{ + get => _bindingFieldName; + set{ + _bindingFieldName = value; + if(_bindingFieldName!=null&&_bindingNodeData!=null){ + OnValueChanged?.Invoke(); + } + } + } + + public NodeData BindingNodeData{ + get => _bindingNodeData; + set{ + _bindingNodeData = value; + if(_bindingFieldName!=null&&_bindingNodeData!=null){ + OnValueChanged?.Invoke(); + } + + } + } + + public InspectorItem(){ + OnValueChanged+= OnValueChangedHandler; + } + + private void OnValueChangedHandler(){ + + + } + ~InspectorItem(){ + OnValueChanged-= OnValueChangedHandler; + } } } \ No newline at end of file diff --git a/TNode/Editor/Inspector/MonoScriptInspector.cs b/TNode/Editor/Inspector/MonoScriptInspector.cs new file mode 100644 index 0000000..a06049a --- /dev/null +++ b/TNode/Editor/Inspector/MonoScriptInspector.cs @@ -0,0 +1,16 @@ +using UnityEditor; +using UnityEditor.AssetImporters; +using UnityEngine; + +namespace TNode.Editor.Inspector{ + // [CustomEditor(typeof(MonoImporter))] + // public class MonoScriptInspector:AssetImporterEditor{ + // public override void OnInspectorGUI(){ + // base.OnInspectorGUI(); + // if(GUILayout.Button("Open")){ + // EditorUtility.OpenWithDefaultApp(AssetDatabase.GetAssetPath(target)); + // } + // } + // } + // +} \ No newline at end of file diff --git a/TNode/Editor/Inspector/MonoScriptInspector.cs.meta b/TNode/Editor/Inspector/MonoScriptInspector.cs.meta new file mode 100644 index 0000000..9441899 --- /dev/null +++ b/TNode/Editor/Inspector/MonoScriptInspector.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 192a51f6578144c5bbddb5cf77685c71 +timeCreated: 1656214219 \ No newline at end of file diff --git a/TNode/Editor/Inspector/NodeInspector.cs b/TNode/Editor/Inspector/NodeInspector.cs index 80eb3dd..a15dabb 100644 --- a/TNode/Editor/Inspector/NodeInspector.cs +++ b/TNode/Editor/Inspector/NodeInspector.cs @@ -1,7 +1,10 @@ -using TNode.BaseViews; +using System.Reflection; +using TNode.BaseViews; using TNode.Models; +using UnityEngine; +using UnityEngine.UIElements; -namespace TNode.Editor.BaseViews{ +namespace TNode.Editor.Inspector{ public class NodeInspector:SimpleGraphSubWindow{ private NodeData _data; @@ -18,8 +21,30 @@ namespace TNode.Editor.BaseViews{ RefreshInspector(); } } + public NodeInspector(){ + var visualTreeAsset = Resources.Load("NodeInspector"); + ConstructWindowBasicSetting(); + BuildWindow(visualTreeAsset); + } private void RefreshInspector(){ + //iterate field of data and get name of every fields,create a new inspector item of appropriate type and add it to the inspector for each field + foreach (var field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)){ + var bindingPath = field.Name; + var type = field.FieldType; + DefaultInspectorItemFactory defaultInspectorItemFactory = new DefaultInspectorItemFactory(); + //Invoke generic function Create<> of default inspector item factory to create an inspector item of appropriate type by reflection + MethodInfo methodInfo = defaultInspectorItemFactory.GetType().GetMethod("Create", BindingFlags.Instance | BindingFlags.Public); + if (methodInfo != null){ + var genericMethod = methodInfo.MakeGenericMethod(type); + var createdInspector = genericMethod.Invoke(defaultInspectorItemFactory,null) as VisualElement; + Add(createdInspector); + if (createdInspector is INodeDataBindingBase castedInspector){ + castedInspector.BindingNodeData = _data; + castedInspector.BindingPath = bindingPath; + } + } + } } diff --git a/TNode/Editor/Inspector/TinyInspector.cs b/TNode/Editor/Inspector/TinyInspector.cs deleted file mode 100644 index 7e28f58..0000000 --- a/TNode/Editor/Inspector/TinyInspector.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace TNode.Editor.Inspector{ - /// - /// Tiny Inspector item is a simple inspector inside a node view - /// - public class TinyInspector{ - - } -} \ No newline at end of file diff --git a/TNode/Editor/Inspector/TinyInspectorItem.cs b/TNode/Editor/Inspector/TinyInspectorItem.cs new file mode 100644 index 0000000..89186c9 --- /dev/null +++ b/TNode/Editor/Inspector/TinyInspectorItem.cs @@ -0,0 +1,13 @@ +using TNode.Models; +using UnityEngine.UIElements; + +namespace TNode.Editor.Inspector{ + /// + /// Tiny Inspector item is a simple inspector item inside a node view ,it monitor node data + /// + /// + public class TinyInspectorItem:VisualElement,INodeDataBinding{ + public string BindingPath{ get; set; } + public NodeData BindingNodeData{ get; set; } + } +} \ No newline at end of file diff --git a/TNode/Editor/Inspector/TinyInspector.cs.meta b/TNode/Editor/Inspector/TinyInspectorItem.cs.meta similarity index 100% rename from TNode/Editor/Inspector/TinyInspector.cs.meta rename to TNode/Editor/Inspector/TinyInspectorItem.cs.meta diff --git a/TNode/Editor/Resources/NodeInsepctor.uxml b/TNode/Editor/Resources/NodeInsepctor.uxml new file mode 100644 index 0000000..1d0f297 --- /dev/null +++ b/TNode/Editor/Resources/NodeInsepctor.uxml @@ -0,0 +1,3 @@ + + + diff --git a/TNode/Editor/Resources/NodeInsepctor.uxml.meta b/TNode/Editor/Resources/NodeInsepctor.uxml.meta new file mode 100644 index 0000000..6de9abc --- /dev/null +++ b/TNode/Editor/Resources/NodeInsepctor.uxml.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 79c615f2df8f4cf45b71df7812d06674 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} diff --git a/TNode/Editor/Resources/ScriptTemplates/NewGraph.cs.txt b/TNode/Editor/Resources/ScriptTemplates/NewGraph.cs.txt index fdccd12..913d60c 100644 --- a/TNode/Editor/Resources/ScriptTemplates/NewGraph.cs.txt +++ b/TNode/Editor/Resources/ScriptTemplates/NewGraph.cs.txt @@ -1,6 +1,7 @@ using TNode.Models; using UnityEngine; using UnityEditor; +using System; [CreateAssetMenu(fileName = "New $GraphClassName$", menuName = "TNode/$GraphClassName$")] [Serializable] public class $GraphClassName$ : GraphData{ diff --git a/TNode/Editor/Resources/ScriptTemplates/NewGraphEditor.cs.txt b/TNode/Editor/Resources/ScriptTemplates/NewGraphEditor.cs.txt index 20018c0..1f5ad7e 100644 --- a/TNode/Editor/Resources/ScriptTemplates/NewGraphEditor.cs.txt +++ b/TNode/Editor/Resources/ScriptTemplates/NewGraphEditor.cs.txt @@ -4,14 +4,14 @@ using UnityEditor.Callbacks; using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.UIElements; - +using System; public class $EditorClassName$ : GraphEditor<$GraphClassName$>{ [OnOpenAsset] public static bool OnOpenAsset(int instanceID, int line){ var graph = EditorUtility.InstanceIDToObject(instanceID) as $GraphClassName$; if (graph != null) { - $GraphClassName$ wnd = GetWindow<$EditorClassName$>(); + var wnd = GetWindow<$EditorClassName$>(); wnd.titleContent = new GUIContent("$GraphClassName$ Editor"); wnd.CreateGUI(); wnd._graphView.Data = graph; diff --git a/TNode/Editor/Resources/ScriptTemplates/NewGraphView.cs.txt b/TNode/Editor/Resources/ScriptTemplates/NewGraphView.cs.txt new file mode 100644 index 0000000..65fdf23 --- /dev/null +++ b/TNode/Editor/Resources/ScriptTemplates/NewGraphView.cs.txt @@ -0,0 +1,9 @@ +using TNode.Models; +using TNode.Attribute; +using TNode.Editor.BaseViews; +[NodeComponent] +public class $GraphViewClassName$ : DataGraphView<$GraphClassName$>{ + + + +} \ No newline at end of file diff --git a/TNode/Editor/Resources/ScriptTemplates/NewGraphView.cs.txt.meta b/TNode/Editor/Resources/ScriptTemplates/NewGraphView.cs.txt.meta new file mode 100644 index 0000000..646231a --- /dev/null +++ b/TNode/Editor/Resources/ScriptTemplates/NewGraphView.cs.txt.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bc741e48f31d4668bd3351eea8a5eaf1 +timeCreated: 1656217566 \ No newline at end of file diff --git a/TNode/Editor/SearchWindowProvider.cs b/TNode/Editor/SearchWindowProvider.cs new file mode 100644 index 0000000..3073585 --- /dev/null +++ b/TNode/Editor/SearchWindowProvider.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using UnityEditor.Experimental.GraphView; +using UnityEngine; + +namespace TNode.Editor{ + public class SearchWindowProvider:ScriptableObject,ISearchWindowProvider{ + public List CreateSearchTree(SearchWindowContext context){ + var list = new List(); + list.Add(new SearchTreeGroupEntry(new GUIContent("Add New Node"), 0)); + list.Add(new SearchTreeGroupEntry(new GUIContent("Add Placemat"), 0)); + return list; + } + + public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context){ + return false; + } + } +} \ No newline at end of file diff --git a/TNode/Editor/SearchWindowProvider.cs.meta b/TNode/Editor/SearchWindowProvider.cs.meta new file mode 100644 index 0000000..d5f817d --- /dev/null +++ b/TNode/Editor/SearchWindowProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1daac5c2c1794f36933cdbc922840769 +timeCreated: 1656314210 \ No newline at end of file diff --git a/TNode/Editor/Tools/GraphEditorCreator/GraphEditorCreator.cs b/TNode/Editor/Tools/GraphEditorCreator/GraphEditorCreator.cs index 472a7cd..f245737 100644 --- a/TNode/Editor/Tools/GraphEditorCreator/GraphEditorCreator.cs +++ b/TNode/Editor/Tools/GraphEditorCreator/GraphEditorCreator.cs @@ -59,6 +59,8 @@ namespace TNode.Editor.Tools.GraphEditorCreator{ _graphClassNameTextField.RegisterCallback>((evt) => { CheckIfTextValid(); }); + + CheckIfTextValid(); } @@ -107,6 +109,7 @@ namespace TNode.Editor.Tools.GraphEditorCreator{ //Query the name of the graph editor string editorName =_editorClassNameTextField.text; string graphName = _graphClassNameTextField.text; + string graphViewName = graphName+"View"; if (editorName == "") { editorName = "NewGraphEditor"; @@ -117,35 +120,32 @@ namespace TNode.Editor.Tools.GraphEditorCreator{ var source = sourceGeneratorForGraphEditor.GenerateGraphEditor(editorName,graphName); var sourceGraph = sourceGeneratorForGraphEditor.GenerateGraph(graphName); + + var sourceGraphView = sourceGeneratorForGraphEditor.GenerateGraphView(graphViewName,graphName); string editorPath = Path.Combine(path, editorName + ".cs"); string graphPath = Path.Combine(path, graphName + ".cs"); + string graphViewPath = Path.Combine(path, graphViewName + ".cs"); File.WriteAllText(editorPath, source); - File.WriteAllText(graphPath, sourceGraph); - - - + File.WriteAllText(graphViewPath, sourceGraphView); //Refresh the AssetDatabase to import the new file - AssetDatabase.Refresh(); - + //Wait for the new file to be imported while (!AssetDatabase.LoadAssetAtPath(editorPath)) { EditorUtility.DisplayProgressBar("Generating Graph Editor", "Please wait while the new graph editor is being imported", 0.5f); EditorApplication.update(); } - //Create an Node Editor Data Instance for the new graph editor + + //Create an NodeAttribute Editor Data Instance for the new graph editor NodeEditorData nodeEditorData = ScriptableObject.CreateInstance(); nodeEditorData.name = editorName; - EditorUtility.SetDirty(nodeEditorData); //Save it at the same folder as the new graph editor string nodeEditorDataPath = Path.Combine(path, editorName + ".asset"); AssetDatabase.CreateAsset(nodeEditorData, nodeEditorDataPath); - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); //Wait for the new file to be imported while (!AssetDatabase.LoadAssetAtPath(nodeEditorDataPath)) { @@ -153,18 +153,12 @@ namespace TNode.Editor.Tools.GraphEditorCreator{ EditorApplication.update(); } var script = AssetDatabase.LoadAssetAtPath(editorPath); - - //Set the mono importer to the current graph editor script MonoImporter monoImporter = AssetImporter.GetAtPath(editorPath) as MonoImporter; if (monoImporter != null) monoImporter.SetDefaultReferences(new string[]{"nodeEditorData"}, new Object[]{nodeEditorData}); - - - - //Refresh the asset ann close it //Mark it dirty diff --git a/TNode/Editor/Tools/GraphEditorCreator/GraphEditorCreator.uxml b/TNode/Editor/Tools/GraphEditorCreator/GraphEditorCreator.uxml index 6906f40..de74e5e 100644 --- a/TNode/Editor/Tools/GraphEditorCreator/GraphEditorCreator.uxml +++ b/TNode/Editor/Tools/GraphEditorCreator/GraphEditorCreator.uxml @@ -6,7 +6,7 @@ - + diff --git a/TNode/Editor/Tools/GraphEditorCreator/SourceGeneratorForGraphEditor.cs b/TNode/Editor/Tools/GraphEditorCreator/SourceGeneratorForGraphEditor.cs index e4e1e40..8e4eeae 100644 --- a/TNode/Editor/Tools/GraphEditorCreator/SourceGeneratorForGraphEditor.cs +++ b/TNode/Editor/Tools/GraphEditorCreator/SourceGeneratorForGraphEditor.cs @@ -22,7 +22,9 @@ namespace TNode.Editor.Tools.GraphEditorCreator{ } var source = template.text.Replace("$EditorClassName$",editorClassName).Replace("$GraphClassName$",graphClassName); return source; - } + } + //what's the shortcut to navigate the files + public string GenerateGraph(string graphClassName,string templateName="NewGraph.cs"){ TextAsset template = Resources.Load("ScriptTemplates/"+templateName); //Check if graph class name is valid @@ -33,5 +35,19 @@ namespace TNode.Editor.Tools.GraphEditorCreator{ var source = template.text.Replace("$GraphClassName$",graphClassName); return source; } + + public string GenerateGraphView(string graphViewClassName,string graphClassName,string templateName="NewGraphView.cs"){ + TextAsset template = Resources.Load("ScriptTemplates/"+templateName); + //Check if graph class name is valid + var regex = new System.Text.RegularExpressions.Regex("^[a-zA-Z0-9_]+$"); + if(!Regex.IsMatch(graphClassName)){ + Debug.LogError("The graph class name is invalid. It must be a valid C# identifier."); + } + if(!Regex.IsMatch(graphViewClassName)){ + Debug.LogError("The graph view name is invalid. It must be a valid C# identifier."); + } + var source = template.text.Replace("$GraphClassName$",graphClassName).Replace("$GraphViewClassName$",graphViewClassName); + return source; + } } } \ No newline at end of file diff --git a/TNode/Models/NodeLink.cs b/TNode/Models/NodeLink.cs index 55266e8..810f3d9 100644 --- a/TNode/Models/NodeLink.cs +++ b/TNode/Models/NodeLink.cs @@ -2,7 +2,7 @@ using Dialogue; namespace TNode.Models{ - //Node links are stored in output side of the two node port. + //NodeAttribute links are stored in output side of the two node port. [Serializable] public class NodeLink{ // public DialogueNodePortData From{ get; }