1.update node view

main
taoria 3 years ago
parent 7cc59a6636
commit 703f34d59b
  1. 4
      Sample/Editor/HelloEditor.cs
  2. 2
      Sample/Editor/HelloGraphView.cs
  3. 8
      TNode/Attribute/ShowInNodeViewAttribute.cs
  4. 3
      TNode/Attribute/ShowInNodeViewAttribute.cs.meta
  5. 14
      TNode/Editor/BaseViews/DataGraphView.cs
  6. 18
      TNode/Editor/BaseViews/NodeView.cs
  7. 6
      TNode/Editor/Cache/NodeEditorExtensions.cs
  8. 7
      TNode/Editor/GraphEditor.cs
  9. 46
      TNode/Editor/Inspector/DefaultInspectorItemFactory.cs
  10. 20
      TNode/Editor/Inspector/InspectorImplementation/DefaultInspectorItem.cs
  11. 12
      TNode/Editor/Inspector/InspectorImplementation/FloatFieldItem.cs
  12. 3
      TNode/Editor/Inspector/InspectorImplementation/FloatFieldItem.cs.meta
  13. 14
      TNode/Editor/Inspector/InspectorImplementation/StringFieldItem.cs
  14. 0
      TNode/Editor/Inspector/InspectorImplementation/StringFieldItem.cs.meta
  15. 12
      TNode/Editor/Inspector/InspectorImplementation/ToggleFieldItem.cs
  16. 3
      TNode/Editor/Inspector/InspectorImplementation/ToggleFieldItem.cs.meta
  17. 32
      TNode/Editor/Inspector/InspectorItem.cs
  18. 25
      TNode/Editor/Inspector/InspectorItemFactory.cs
  19. 0
      TNode/Editor/Inspector/InspectorItemFactory.cs.meta
  20. 21
      TNode/Editor/Inspector/NodeInspector.cs
  21. 51
      TNode/Editor/Inspector/NodeInspectorInNode.cs
  22. 3
      TNode/Editor/Inspector/NodeInspectorInNode.cs.meta
  23. 4
      TNode/Editor/Resources/NodeInspector.uxml
  24. 3
      TNode/Editor/SearchWindowProvider.cs
  25. 4
      TNode/Models/NodeData.cs

@ -18,5 +18,9 @@ namespace Sample.Editor{
}
return false;
}
public HelloEditor(){
}
}
}

@ -9,5 +9,7 @@ namespace Sample.Editor{
public override void OnGraphViewCreate(){
CreateInspector();
}
}
}

@ -0,0 +1,8 @@
using System;
namespace TNode.Attribute{
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class ShowInNodeViewAttribute:System.Attribute{
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3486b937bc1e4a95aa03e842a23fdf72
timeCreated: 1656584304

@ -178,12 +178,24 @@ namespace TNode.Editor.BaseViews{
public virtual void CreateInspector(){
NodeInspector nodeInspector = new NodeInspector();
nodeInspector.SetPosition(new Rect(200,200,200,600));
this.Add(nodeInspector);
_nodeInspector = nodeInspector;
_isInspectorOn = true;
}
public virtual void DestroyInspector(){
if(_nodeInspector!=null){
this.Remove(_nodeInspector);
_nodeInspector = null;
}
_isInspectorOn = false;
}
public virtual void SetInspector(NodeInspector nodeInspector){
_nodeInspector = nodeInspector;
if (!_isInspectorOn){
_isInspectorOn = true;
}
}
public virtual void OnGraphViewCreate(){

@ -1,7 +1,9 @@
using TNode.Models;
using TNode.Editor.Inspector;
using TNode.Models;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEditor.UIElements;
using UnityEngine;
namespace TNode.Editor.BaseViews{
@ -9,11 +11,14 @@ namespace TNode.Editor.BaseViews{
public abstract class NodeView<T> : Node,INodeView where T:NodeData,new(){
protected T _data;
private readonly NodeInspectorInNode _nodeInspectorInNode;
public T Data{
get => _data;
set{
_data = value;
OnDataChanged?.Invoke(value);
}
}
public sealed override string title{
@ -24,14 +29,25 @@ namespace TNode.Editor.BaseViews{
protected NodeView(){
OnDataChanged+=OnDataChangedHandler;
_nodeInspectorInNode = new NodeInspectorInNode(){
name = "nodeInspectorInNode"
};
this.extensionContainer.Add(_nodeInspectorInNode);
}
private void OnDataChangedHandler(T obj){
this.title = _data.nodeName;
if (_nodeInspectorInNode != null){
_nodeInspectorInNode.Data = obj;
this.RefreshExpandedState();
this.expanded = true;
}
}
public void SetNodeData(NodeData nodeData){
Data = (T)nodeData;
}
public NodeData GetNodeData(){

@ -5,6 +5,7 @@ using TNode.Attribute;
using TNode.BaseViews;
using TNode.Editor;
using TNode.Editor.BaseViews;
using TNode.Editor.Inspector;
using TNode.Models;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
@ -57,14 +58,13 @@ namespace TNode.Cache{
}
}
}
private readonly Type[] _acceptedTypesForGenericToSpecific = new Type[]{typeof(NodeView<>),typeof(DataGraphView<>),typeof(InspectorItem<>)};
private void SetNodeComponentAttribute(Type type){
foreach (var attribute in type.GetCustomAttributes(typeof(NodeComponentAttribute), false)){
//fetch this type 's parent class
var parent = type.BaseType;
//Check if this type is a generic type and is a generic type of NodeView or DataGraphView
if (parent is{IsGenericType: true} && (parent.GetGenericTypeDefinition() == typeof(NodeView<>) ||
parent.GetGenericTypeDefinition() == typeof(DataGraphView<>))){
if (parent is{IsGenericType: true} && _acceptedTypesForGenericToSpecific.Contains(parent.GetGenericTypeDefinition())){
//Get the generic type of this type
//Add this type to the dictionary
FromGenericToSpecific.Add(parent, type);

@ -2,6 +2,7 @@ using Codice.CM.Common;
using TNode.BaseViews;
using TNode.Cache;
using TNode.Editor.BaseViews;
using TNode.Editor.Inspector;
using TNode.Editor.Model;
using TNode.Models;
using UnityEditor;
@ -35,20 +36,16 @@ namespace TNode.Editor{
DefineGraphEditorActions();
OnCreate();
}
private void BuildGraphView(){
_graphView = NodeEditorExtensions.CreateInstance<DataGraphView<T>>();
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);

@ -1,46 +0,0 @@
using System;
using TNode.Cache;
using TNode.Editor.Inspector.InspectorImplementation;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace TNode.Editor.Inspector{
public class DefaultInspectorItemFactory{
public InspectorItem<T> Create<T>(){
//Check type of GraphDataType
var hasSpecificType = NodeEditorExtensions.HasSpecificType<InspectorItem<T>>();
if (hasSpecificType){
return NodeEditorExtensions.CreateInstance<InspectorItem<T>>();
}
else{
return DefaultInspectorItem<T>();
}
}
public static InspectorItem<T> DefaultInspectorItem<T>(){
DefaultInspectorItem<T> item = new DefaultInspectorItem<T>();
if (typeof(string) == typeof(T)){
var textField = new TextField(){
name = "StringTextField"
};
item.foldOut.Add(textField);
textField.RegisterCallback<ChangeEvent<string>>(e => {
Debug.Log(item.BindingNodeData);
Debug.Log(item.BindingPath);
item.BindingNodeData.GetType().GetField(item.BindingPath).SetValue(item.BindingNodeData, e.newValue);
if (item.parent.parent is NodeInspector nodeInspector){
Debug.Log("item 's parent 's parent is exactly a node inspector");
nodeInspector.NodeView.OnDataModified();
}
});
}
return item;
}
}
}

@ -1,20 +0,0 @@
using UnityEngine.UIElements;
namespace TNode.Editor.Inspector.InspectorImplementation{
public class DefaultInspectorItem<T>:InspectorItem<T>{
public readonly Foldout foldOut;
public DefaultInspectorItem():base(){
foldOut = new Foldout{
text = ""
};
this.Add(foldOut);
OnValueChanged += () => {
foldOut.text = this.BindingPath;
var textField = this.Q<TextField>();
if(textField != null){
textField.value = this.Value.ToString();
}
};
}
}
}

@ -0,0 +1,12 @@
using System;
using TNode.Attribute;
using UnityEngine.UIElements;
namespace TNode.Editor.Inspector.InspectorImplementation{
[NodeComponent]
public class FloatFieldItem:InspectorItem<float>{
public FloatFieldItem():base(){
CreateBindable(new FloatField());
}
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 932de5e7a487475aa764dd819cc33aa0
timeCreated: 1656583186

@ -0,0 +1,14 @@
using TNode.Attribute;
using UnityEngine.UIElements;
namespace TNode.Editor.Inspector.InspectorImplementation{
/// <summary>
/// Force these element to bind native c# property
/// </summary>
[NodeComponent]
public class StringFieldItem:InspectorItem<string>{
public StringFieldItem():base(){
CreateBindable(new TextField());
}
}
}

@ -0,0 +1,12 @@
using TNode.Attribute;
using UnityEngine.UIElements;
namespace TNode.Editor.Inspector.InspectorImplementation{
[NodeComponent]
public class ToggleFieldItem:InspectorItem<bool>{
public ToggleFieldItem(){
CreateBindable(new Toggle());
}
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d009d4819d604971976932b1d8f40bad
timeCreated: 1656580623

@ -7,6 +7,7 @@ namespace TNode.Editor.Inspector{
public abstract class InspectorItem<T>:VisualElement,INodeDataBinding<T>{
private NodeData _bindingNodeData;
private string _bindingFieldName;
protected BaseField<T> Bindable;
protected event System.Action OnValueChanged;
public string BindingPath{
@ -46,13 +47,40 @@ namespace TNode.Editor.Inspector{
}
protected T Value => GetValue();
protected void SetValue(T value){
var fieldInfo = _bindingNodeData.GetType().GetField(BindingPath, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
Debug.Log(fieldInfo);
Debug.Log(fieldInfo?.FieldType );
if (fieldInfo != null && fieldInfo.FieldType == typeof(T)){
fieldInfo.SetValue(_bindingNodeData,value);
//if value changed ,notify node inspector's current inspecting node view
if (parent.parent is NodeInspector nodeInspector){
nodeInspector.NodeView.OnDataModified();
}
}
else{
Debug.LogError("Wrong Type for current node data");
}
}
public InspectorItem(){
OnValueChanged+= OnValueChangedHandler;
}
public void CreateBindable(BaseField<T> bindable){
Bindable = bindable;
this.Add(Bindable);
Bindable?.RegisterValueChangedCallback(e => {
SetValue(e.newValue);
});
}
private void OnValueChangedHandler(){
Bindable = this.Q<BaseField<T>>();
if(Bindable!= null){
Bindable.value = Value;
Bindable.label = BindingPath;
}
}
~InspectorItem(){
OnValueChanged-= OnValueChangedHandler;

@ -0,0 +1,25 @@
using System;
using TNode.Cache;
using TNode.Editor.Inspector.InspectorImplementation;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace TNode.Editor.Inspector{
public class InspectorItemFactory{
public InspectorItem<T> Create<T>(){
//Check type of GraphDataType
var hasSpecificType = NodeEditorExtensions.HasSpecificType<InspectorItem<T>>();
Debug.Log(typeof(InspectorItem<T>));
Debug.Log(hasSpecificType);
if (hasSpecificType){
return NodeEditorExtensions.CreateInstance<InspectorItem<T>>();
}
return null;
}
}
}

@ -1,14 +1,19 @@
using System.Reflection;
using System;
using System.Collections.Generic;
using System.Reflection;
using TNode.BaseViews;
using TNode.Editor.BaseViews;
using TNode.Models;
using Unity.VisualScripting;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace TNode.Editor.Inspector{
public class NodeInspector:SimpleGraphSubWindow{
private NodeData _data;
public NodeData Data{
get => _data;
set{
@ -26,6 +31,7 @@ namespace TNode.Editor.Inspector{
}
}
public NodeInspector(){
this.capabilities |= Capabilities.Resizable;
style.position = new StyleEnum<Position>(Position.Absolute);
var visualTreeAsset = Resources.Load<VisualTreeAsset>("NodeInspector");
Debug.Log(visualTreeAsset);
@ -33,20 +39,21 @@ namespace TNode.Editor.Inspector{
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
var body = this.Q("InspectorBody");
body.Clear();
body.Add(new Label(_data.nodeName));
body.StretchToParentSize();
foreach (var field in _data.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)){
var bindingPath = field.Name;
var type = field.FieldType;
DefaultInspectorItemFactory defaultInspectorItemFactory = new DefaultInspectorItemFactory();
InspectorItemFactory inspectorItemFactory = new InspectorItemFactory();
//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);
MethodInfo methodInfo = inspectorItemFactory.GetType().GetMethod("Create", BindingFlags.Instance | BindingFlags.Public);
if (methodInfo != null){
var genericMethod = methodInfo.MakeGenericMethod(type);
var createdItem = genericMethod.Invoke(defaultInspectorItemFactory,null) as VisualElement;
var createdItem = genericMethod.Invoke(inspectorItemFactory,null) as VisualElement;
body.Add(createdItem);
if (createdItem is INodeDataBindingBase castedItem){
@ -55,8 +62,6 @@ namespace TNode.Editor.Inspector{
}
}
}
}
}
}

@ -0,0 +1,51 @@
using System.Reflection;
using TNode.Attribute;
using TNode.Models;
using UnityEngine;
using UnityEngine.UIElements;
namespace TNode.Editor.Inspector{
public class NodeInspectorInNode:VisualElement{
private NodeData _data;
public NodeData Data{
get => _data;
set{
_data = value;
UpdateData();
}
}
private void UpdateData(){
Debug.Log(_data);
if (_data != null){
RefreshInspector();
}
}
private void RefreshInspector(){
Clear();
Debug.Log("In Node node inspector refresh for new data " + _data);
InspectorItemFactory inspectorItemFactory = new InspectorItemFactory();
foreach (var field in _data.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)){
var bindingPath = field.Name;
var type = field.FieldType;
//check if the field has ShowInNodeView attribute
var showInNodeViewAttribute = field.GetCustomAttribute<ShowInNodeViewAttribute>()!=null;
if(!showInNodeViewAttribute)
continue;
//Invoke generic function Create<> of default inspector item factory to create an inspector item of appropriate type by reflection
MethodInfo methodInfo = inspectorItemFactory.GetType().GetMethod("Create", BindingFlags.Instance | BindingFlags.Public);
if (methodInfo != null){
var genericMethod = methodInfo.MakeGenericMethod(type);
var createdItem = genericMethod.Invoke(inspectorItemFactory,null) as VisualElement;
Add(createdItem);
if (createdItem is INodeDataBindingBase castedItem){
castedItem.BindingNodeData = _data;
castedItem.BindingPath = bindingPath;
}
}
}
}
}
}

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0ab3baa9312e4beaa12e5f2131f09969
timeCreated: 1656584377

@ -1,3 +1,3 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<ui:VisualElement name="InspectorBody" style="height: 458px; background-color: rgba(36, 36, 36, 255);" />
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<ui:VisualElement name="InspectorBody" style="height: 600px; width: 400px; background-color: rgb(65, 65, 65);" />
</ui:UXML>

@ -47,8 +47,7 @@ namespace TNode.Editor{
//Check if type is derived from NodeData
if (typeof(NodeData).IsAssignableFrom(type)){
//Make an instance of the type
var nodeData = CreateInstance(type) as NodeData;
if (nodeData != null){
if (Activator.CreateInstance(type) is NodeData nodeData){
nodeData.nodeName = "New Node";
((IDataGraphView) _graphView).AddTNode(nodeData, new Rect(localPos.x, localPos.y, 100, 100));
}

@ -1,4 +1,5 @@
using System;
using TNode.Attribute;
using TNode.BaseModels;
using UnityEngine;
@ -11,12 +12,13 @@ namespace TNode.Models{
///
/// </summary>
[Serializable]
public class NodeData:ScriptableObject,IModel{
public class NodeData:IModel{
public NodeData() : base(){
//Object Registration
}
public string nodeName;
[ShowInNodeView]
public bool entryPoint;
// #if UNITY_EDITOR
// public Rect rect;

Loading…
Cancel
Save