1
0
mirror of https://github.com/Siccity/xNode.git synced 2026-03-26 22:49:02 +08:00

Refactored OdinInspector integration.

This commit is contained in:
Kailey Joanette 2019-09-24 19:22:49 -04:00
parent 979bd5f7cf
commit 489767b313
15 changed files with 722 additions and 110 deletions

View File

@ -0,0 +1,98 @@
#if UNITY_EDITOR && ODIN_INSPECTOR
using Sirenix.OdinInspector.Editor;
using System;
using UnityEditor;
using UnityEngine;
using XNode;
using static XNode.Node;
namespace XNodeEditor.Odin
{
internal abstract class AsDynamicPortAtribute : System.Attribute
{
internal string fieldName { get; set; }
internal int index { get; set; }
internal Node Node { get; set; }
internal ConnectionType connectionType { get; set; }
internal ShowBackingValue backingValue { get; set; }
internal NodePort Port
{
get
{
return Node.GetPort( $"{fieldName} {index}" );
}
}
}
internal class AsDynamicPortNoDataAtribute : AsDynamicPortAtribute { }
internal class AsDynamicPortWithDataAtribute : AsDynamicPortAtribute { }
internal struct AsDynamicPortScope : IDisposable
{
public AsDynamicPortScope( NodePort port )
{
EditorGUILayout.BeginVertical();
var rect = GUILayoutUtility.GetRect( 0f, float.MaxValue, 0f, 0f, GUI.skin.label, GUILayout.ExpandWidth( true ) );
if ( NodeEditor.isNodeEditor )
{
if ( port.IsInput )
{
NodeEditorGUILayout.PortField( new Vector2( rect.xMin - 42, rect.center.y ), port );
}
else
{
NodeEditorGUILayout.PortField( new Vector2( rect.xMax + 21, rect.center.y ), port );
}
}
EditorGUILayout.BeginHorizontal();
EditorGUILayout.BeginVertical();
}
public void Dispose()
{
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
}
[DrawerPriority( 0.4, 0, 0 )]
internal class AsDynamicPortNoDataAttributeDrawer<T> : OdinAttributeDrawer<AsDynamicPortNoDataAtribute, T>
{
protected override void DrawPropertyLayout( GUIContent label )
{
if ( Attribute.Port == null )
return;
using ( new AsDynamicPortScope( Attribute.Port ) )
CallNextDrawer( label );
}
}
[DrawerPriority( 0.4, 0, 0 )]
internal class AsDynamicPortWithDataAtributeDrawer<T> : OdinAttributeDrawer<AsDynamicPortWithDataAtribute, T>
{
protected bool drawData = false;
protected override void DrawPropertyLayout( GUIContent label )
{
if ( Attribute.Port == null )
return;
if ( Event.current.type == EventType.Layout )
drawData = Attribute.backingValue == ShowBackingValue.Always || Attribute.backingValue == ShowBackingValue.Unconnected && !Attribute.Port.IsConnected;
using ( new AsDynamicPortScope( Attribute.Port ) )
{
if ( drawData )
CallNextDrawer( label );
else
EditorGUILayout.LabelField( label );
}
}
}
}
#endif

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 2fd590b2e9ea0bd49b6986a2ca9010ab
guid: 0ef93b42a7d5fe8459b6755d72583900
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -0,0 +1,83 @@
#if UNITY_EDITOR && ODIN_INSPECTOR
using Sirenix.OdinInspector.Editor;
using System;
using UnityEditor;
using UnityEngine;
using XNode;
using static XNode.Node;
namespace XNodeEditor.Odin
{
internal struct AsStaticPortScope : IDisposable
{
public AsStaticPortScope( NodePort port )
{
EditorGUILayout.BeginVertical();
var rect = GUILayoutUtility.GetRect( 0f, float.MaxValue, 0f, 0f, GUI.skin.label, GUILayout.ExpandWidth( true ) );
if ( NodeEditor.isNodeEditor )
{
if ( port.IsInput )
{
NodeEditorGUILayout.PortField( new Vector2( rect.xMin - 18, rect.center.y + 2 ), port );
}
else
{
NodeEditorGUILayout.PortField( new Vector2( rect.xMax + 2, rect.center.y + 2 ), port );
}
}
EditorGUILayout.BeginHorizontal();
EditorGUILayout.BeginVertical();
}
public void Dispose()
{
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
}
[DrawerPriority( 0.4, 0, 0 )]
internal class InputAttributeDrawer<T> : OdinAttributeDrawer<InputAttribute, T>
{
protected bool drawData = false;
protected override void DrawPropertyLayout( GUIContent label )
{
NodePort port = ( Property.Tree.UnitySerializedObject.targetObject as Node ).GetInputPort( Property.Name );
if ( Event.current.type == EventType.Layout )
drawData = Attribute.backingValue == ShowBackingValue.Always || Attribute.backingValue == ShowBackingValue.Unconnected && !port.IsConnected;
using ( new AsStaticPortScope( port ) )
{
if ( drawData )
CallNextDrawer( label );
else
EditorGUILayout.LabelField( label );
}
}
}
[DrawerPriority( 0.4, 0, 0 )]
internal class OutputAttributeDrawer<T> : OdinAttributeDrawer<OutputAttribute, T>
{
protected bool drawData = false;
protected override void DrawPropertyLayout( GUIContent label )
{
NodePort port = ( Property.Tree.UnitySerializedObject.targetObject as Node ).GetOutputPort( Property.Name );
if ( Event.current.type == EventType.Layout )
drawData = Attribute.backingValue == ShowBackingValue.Always || Attribute.backingValue == ShowBackingValue.Unconnected && !port.IsConnected;
using ( new AsStaticPortScope( port ) )
{
if ( drawData )
CallNextDrawer( label );
else
EditorGUILayout.LabelField( label );
}
}
}
}
#endif

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e7ebd8f2b42e2384aa109551dc46af88
guid: 36e90d7590dbcad418bc8ca94192d5e2
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -0,0 +1,219 @@
#if UNITY_EDITOR && ODIN_INSPECTOR
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using XNode;
using static XNode.Node;
namespace XNodeEditor.Odin
{
[ResolverPriority( 10 )]
public class DynamicPortListBackedResolver<TList, TElement> : StrongListPropertyResolver<TList, TElement>
where TList : IList<TElement>
{
public override bool CanResolveForPropertyFilter( InspectorProperty property )
{
var input = property.GetAttribute<InputAttribute>();
if ( input != null )
return input.dynamicPortList;
var output = property.GetAttribute<OutputAttribute>();
if ( output != null )
return output.dynamicPortList;
return false;
}
private Dictionary<int, InspectorPropertyInfo> childInfos = new Dictionary<int, InspectorPropertyInfo>();
public override InspectorPropertyInfo GetChildInfo( int childIndex )
{
if ( childIndex < 0 || childIndex >= this.ChildCount )
{
throw new IndexOutOfRangeException();
}
InspectorPropertyInfo result;
if ( !this.childInfos.TryGetValue( childIndex, out result ) )
{
var attributes = this.Property.Attributes.Where( attr => !attr.GetType().IsDefined( typeof( DontApplyToListElementsAttribute ), true ) );
var labelTextAttribute = attributes.OfType<LabelTextAttribute>().SingleOrDefault();
var hideLabelAttribute = attributes.OfType<HideLabelAttribute>().SingleOrDefault();
var listDrawerSettingsAttribute = attributes.OfType<ListDrawerSettingsAttribute>().SingleOrDefault();
if ( listDrawerSettingsAttribute == null )
{
listDrawerSettingsAttribute = new ListDrawerSettingsAttribute() { Expanded = true, ShowPaging = false };
}
else
{
listDrawerSettingsAttribute.Expanded = true;
listDrawerSettingsAttribute.ShowPaging = false;
}
attributes = attributes
.Append( GetPortAttribute( Property.Name, childIndex ) )
.AppendIf( labelTextAttribute == null && hideLabelAttribute == null, new LabelTextAttribute( $"{Property.Name} {childIndex}" ) );
result = InspectorPropertyInfo.CreateValue(
name: CollectionResolverUtilities.DefaultIndexToChildName( childIndex ),
order: childIndex,
serializationBackend: this.Property.BaseValueEntry.SerializationBackend,
new GetterSetter<TList, TElement>(
getter: ( ref TList list ) => list[childIndex],
setter: ( ref TList list, TElement element ) => list[childIndex] = element ),
attributes: attributes.ToArray() );
this.childInfos[childIndex] = result;
}
return result;
}
internal AsDynamicPortWithDataAtribute GetPortAttribute( string fieldName, int index )
{
return new AsDynamicPortWithDataAtribute()
{
fieldName = fieldName,
index = index,
Node = node,
connectionType = connectionType,
backingValue = backingValue
};
}
protected override void Add( TList collection, object value )
{
int nextId = this.ChildCount;
if ( IsInput )
this.node.AddDynamicInput( typeof( TElement ), connectionType, typeConstraint, $"{Property.Name} {nextId}" );
else
this.node.AddDynamicOutput( typeof( TElement ), connectionType, typeConstraint, $"{Property.Name} {nextId}" );
lastRemovedConnections.Clear();
base.Add( collection, value );
}
protected override void InsertAt( TList collection, int index, object value )
{
int nextId = this.ChildCount;
// Remove happens before insert and we lose all the connections
// Add a new port at the end
if ( IsInput )
this.node.AddDynamicInput( typeof( TElement ), connectionType, typeConstraint, $"{Property.Name} {nextId}" );
else
this.node.AddDynamicOutput( typeof( TElement ), connectionType, typeConstraint, $"{Property.Name} {nextId}" );
var dynamicPorts = this.ports;
// Move everything down to make space
for ( int k = dynamicPorts.Count - 1; k > index; --k )
{
for ( int j = 0; j < dynamicPorts[k - 1].ConnectionCount; j++ )
{
XNode.NodePort other = dynamicPorts[k - 1].GetConnection( j );
dynamicPorts[k - 1].Disconnect( other );
dynamicPorts[k].Connect( other );
}
}
// Let's just re-add connections to this node that were probably his
foreach ( var c in lastRemovedConnections )
dynamicPorts[index].Connect( c );
lastRemovedConnections.Clear();
base.InsertAt( collection, index, value );
}
protected override void Remove( TList collection, object value )
{
int index = collection.IndexOf( (TElement)value );
RemoveAt( collection, index );
}
protected List<NodePort> lastRemovedConnections = new List<NodePort>();
protected override void RemoveAt( TList collection, int index )
{
var dynamicPorts = this.ports;
if ( dynamicPorts[index] == null )
{
Debug.LogWarning( "No port found at index " + index + " - Skipped" );
}
else if ( dynamicPorts.Count <= index )
{
Debug.LogWarning( "DynamicPorts[" + index + "] out of range. Length was " + dynamicPorts.Count + " - Skipped" );
}
else
{
lastRemovedConnections.Clear();
lastRemovedConnections.AddRange( dynamicPorts[index].GetConnections() );
// Clear the removed ports connections
dynamicPorts[index].ClearConnections();
// Move following connections one step up to replace the missing connection
for ( int k = index + 1; k < dynamicPorts.Count; k++ )
{
for ( int j = 0; j < dynamicPorts[k].ConnectionCount; j++ )
{
XNode.NodePort other = dynamicPorts[k].GetConnection( j );
dynamicPorts[k].Disconnect( other );
dynamicPorts[k - 1].Connect( other );
}
}
// Remove the last dynamic port, to avoid messing up the indexing
node.RemoveDynamicPort( dynamicPorts[dynamicPorts.Count() - 1].fieldName );
}
base.RemoveAt( collection, index );
}
protected override void Clear( TList collection )
{
foreach ( var port in ports )
node.RemoveDynamicPort( port );
lastRemovedConnections.Clear();
base.Clear( collection );
}
protected Node node => ( Property.Tree.UnitySerializedObject.targetObject as Node );
protected List<NodePort> ports
{
get
{
// This created a lot of garbage
List<NodePort> dynamicPorts = new List<NodePort>();
for ( int i = 0; i < int.MaxValue; ++i )
{
var nodePort = node.GetPort( $"{Property.Name} {i}" );
if ( nodePort == null )
break;
dynamicPorts.Add( nodePort );
}
return dynamicPorts;
}
}
protected bool IsInput => Property.GetAttribute<InputAttribute>() != null;
public ConnectionType connectionType => IsInput ? Property.GetAttribute<InputAttribute>().connectionType : Property.GetAttribute<OutputAttribute>().connectionType;
public TypeConstraint typeConstraint => IsInput ? Property.GetAttribute<InputAttribute>().typeConstraint : Property.GetAttribute<OutputAttribute>().typeConstraint;
public ShowBackingValue backingValue => IsInput ? Property.GetAttribute<InputAttribute>().backingValue : Property.GetAttribute<OutputAttribute>().backingValue;
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f8fa0ef545c9f5049bbc8da047874fd1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,250 @@
#if UNITY_EDITOR && ODIN_INSPECTOR
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.OdinInspector.Editor.Drawers;
using Sirenix.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using XNode;
using XNodeEditor.Odin;
using static XNode.Node;
namespace XNodeEditor
{
[DrawerPriority( 0.4, 0, 0 )]
public class SillyCollectionDrawer : CollectionDrawer<int>
{
}
public class DynamicPortListNoDataResolver<T> : DynamicPortListNoDataResolver<T, NodePort> { }
public class DynamicPortListNoDataResolver<TNotAList, TElement> : BaseOrderedCollectionResolver<TNotAList>
where TElement : NodePort
{
public override bool CanResolveForPropertyFilter( InspectorProperty property )
{
var input = property.GetAttribute<InputAttribute>();
if ( input != null )
return input.dynamicPortList;
var output = property.GetAttribute<OutputAttribute>();
if ( output != null )
return output.dynamicPortList;
return false;
}
private Dictionary<int, InspectorPropertyInfo> childInfos = new Dictionary<int, InspectorPropertyInfo>();
public override InspectorPropertyInfo GetChildInfo( int childIndex )
{
if ( childIndex < 0 || childIndex >= this.ChildCount )
{
throw new IndexOutOfRangeException();
}
InspectorPropertyInfo result;
if ( !this.childInfos.TryGetValue( childIndex, out result ) )
{
var attributes = this.Property.Attributes.Where( attr => !attr.GetType().IsDefined( typeof( DontApplyToListElementsAttribute ), true ) );
var labelTextAttribute = attributes.OfType<LabelTextAttribute>().SingleOrDefault();
var hideLabelAttribute = attributes.OfType<HideLabelAttribute>().SingleOrDefault();
var listDrawerSettingsAttribute = attributes.OfType<ListDrawerSettingsAttribute>().SingleOrDefault();
if ( listDrawerSettingsAttribute == null )
{
listDrawerSettingsAttribute = new ListDrawerSettingsAttribute() { Expanded = true, ShowPaging = false };
}
else
{
listDrawerSettingsAttribute.Expanded = true;
listDrawerSettingsAttribute.ShowPaging = false;
}
attributes = attributes
.Append( GetPortAttribute( Property.Name, childIndex ) )
.AppendIf( labelTextAttribute == null && hideLabelAttribute == null, new LabelTextAttribute( $"{Property.Name} {childIndex}" ) );
result = InspectorPropertyInfo.CreateValue(
name: CollectionResolverUtilities.DefaultIndexToChildName( childIndex ),
order: childIndex,
serializationBackend: this.Property.BaseValueEntry.SerializationBackend,
new GetterSetter<TNotAList, TElement>(
getter: ( ref TNotAList list ) => ports[childIndex], // Return absolutely nothing? Return a port?
setter: ( ref TNotAList list, TElement element ) => ports[childIndex] = element ),
attributes: attributes.ToArray() );
this.childInfos[childIndex] = result;
}
return result;
}
internal AsDynamicPortNoDataAtribute GetPortAttribute( string fieldName, int index )
{
return new AsDynamicPortNoDataAtribute()
{
fieldName = fieldName,
index = index,
Node = node,
connectionType = connectionType,
backingValue = backingValue
};
}
protected override void Add( TNotAList collection, object value )
{
int nextId = this.ChildCount;
if ( IsInput )
this.node.AddDynamicInput( typeof( TNotAList ), connectionType, typeConstraint, $"{Property.Name} {nextId}" );
else
this.node.AddDynamicOutput( typeof( TNotAList ), connectionType, typeConstraint, $"{Property.Name} {nextId}" );
lastRemovedConnections.Clear();
//base.Add( collection, value );
}
protected override void InsertAt( TNotAList collection, int index, object value )
{
int nextId = this.ChildCount;
// Remove happens before insert and we lose all the connections
// Add a new port at the end
if ( IsInput )
this.node.AddDynamicInput( typeof( TNotAList ), connectionType, typeConstraint, $"{Property.Name} {nextId}" );
else
this.node.AddDynamicOutput( typeof( TNotAList ), connectionType, typeConstraint, $"{Property.Name} {nextId}" );
var dynamicPorts = this.ports;
// Move everything down to make space
for ( int k = dynamicPorts.Count - 1; k > index; --k )
{
for ( int j = 0; j < dynamicPorts[k - 1].ConnectionCount; j++ )
{
XNode.NodePort other = dynamicPorts[k - 1].GetConnection( j );
dynamicPorts[k - 1].Disconnect( other );
dynamicPorts[k].Connect( other );
}
}
// Let's just re-add connections to this node that were probably his
foreach ( var c in lastRemovedConnections )
dynamicPorts[index].Connect( c );
lastRemovedConnections.Clear();
//base.InsertAt( collection, index, value );
}
protected override void Remove( TNotAList collection, object value )
{
//int index = collection.IndexOf( (TElement)value );
//RemoveAt( collection, index );
throw new NotImplementedException();
}
protected List<NodePort> lastRemovedConnections = new List<NodePort>();
protected override void RemoveAt( TNotAList collection, int index )
{
var dynamicPorts = this.ports;
if ( dynamicPorts[index] == null )
{
Debug.LogWarning( "No port found at index " + index + " - Skipped" );
}
else if ( dynamicPorts.Count <= index )
{
Debug.LogWarning( "DynamicPorts[" + index + "] out of range. Length was " + dynamicPorts.Count + " - Skipped" );
}
else
{
lastRemovedConnections.Clear();
lastRemovedConnections.AddRange( dynamicPorts[index].GetConnections() );
// Clear the removed ports connections
dynamicPorts[index].ClearConnections();
// Move following connections one step up to replace the missing connection
for ( int k = index + 1; k < dynamicPorts.Count; k++ )
{
for ( int j = 0; j < dynamicPorts[k].ConnectionCount; j++ )
{
XNode.NodePort other = dynamicPorts[k].GetConnection( j );
dynamicPorts[k].Disconnect( other );
dynamicPorts[k - 1].Connect( other );
}
}
// Remove the last dynamic port, to avoid messing up the indexing
node.RemoveDynamicPort( dynamicPorts[dynamicPorts.Count() - 1].fieldName );
}
//base.RemoveAt( collection, index );
}
protected override void Clear( TNotAList collection )
{
foreach ( var port in ports )
node.RemoveDynamicPort( port );
lastRemovedConnections.Clear();
//base.Clear( collection );
}
public override bool ChildPropertyRequiresRefresh( int index, InspectorPropertyInfo info )
{
return false;
}
protected override bool CollectionIsReadOnly( TNotAList collection )
{
return false;
}
protected override int GetChildCount( TNotAList value )
{
return ports.Count;
}
public override int ChildNameToIndex( string name )
{
return CollectionResolverUtilities.DefaultChildNameToIndex( name );
}
public override Type ElementType => typeof( TElement );
protected Node node => ( Property.Tree.UnitySerializedObject.targetObject as Node );
protected List<TElement> ports
{
get
{
// This created a lot of garbage
List<TElement> dynamicPorts = new List<TElement>();
for ( int i = 0; i < int.MaxValue; ++i )
{
var nodePort = node.GetPort( $"{Property.Name} {i}" );
if ( nodePort == null )
break;
dynamicPorts.Add( nodePort as TElement );
}
return dynamicPorts;
}
}
protected bool IsInput => Property.GetAttribute<InputAttribute>() != null;
public ConnectionType connectionType => IsInput ? Property.GetAttribute<InputAttribute>().connectionType : Property.GetAttribute<OutputAttribute>().connectionType;
public TypeConstraint typeConstraint => IsInput ? Property.GetAttribute<InputAttribute>().typeConstraint : Property.GetAttribute<OutputAttribute>().typeConstraint;
public ShowBackingValue backingValue => IsInput ? Property.GetAttribute<InputAttribute>().backingValue : Property.GetAttribute<OutputAttribute>().backingValue;
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 16bd57b189b3213449470c2dce67f5ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,19 +1,20 @@
#if UNITY_EDITOR && ODIN_INSPECTOR
using Sirenix.OdinInspector.Editor;
using System;
using System.Collections.Generic;
using System.Reflection;
using Sirenix.OdinInspector.Editor;
using UnityEngine;
using XNode;
namespace XNodeEditor {
namespace XNodeEditor
{
internal class OdinNodeInGraphAttributeProcessor<T> : OdinAttributeProcessor<T> where T : Node {
public override bool CanProcessSelfAttributes(InspectorProperty property) {
return false;
}
public override bool CanProcessChildMemberAttributes(InspectorProperty parentProperty, MemberInfo member) {
if (!NodeEditor.inNodeEditor)
if (!NodeEditor.isNodeEditor)
return false;
if (member.MemberType == MemberTypes.Field) {

View File

@ -1,49 +0,0 @@
#if UNITY_EDITOR && ODIN_INSPECTOR
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities.Editor;
using UnityEngine;
using XNode;
namespace XNodeEditor {
public class InputAttributeDrawer : OdinAttributeDrawer<XNode.Node.InputAttribute> {
protected override bool CanDrawAttributeProperty(InspectorProperty property) {
Node node = property.Tree.WeakTargets[0] as Node;
return node != null;
}
protected override void DrawPropertyLayout(GUIContent label) {
Node node = Property.Tree.WeakTargets[0] as Node;
NodePort port = node.GetInputPort(Property.Name);
if (!NodeEditor.inNodeEditor) {
if (Attribute.backingValue == XNode.Node.ShowBackingValue.Always || Attribute.backingValue == XNode.Node.ShowBackingValue.Unconnected && !port.IsConnected)
CallNextDrawer(label);
return;
}
if (Property.Tree.WeakTargets.Count > 1) {
SirenixEditorGUI.WarningMessageBox("Cannot draw ports with multiple nodes selected");
return;
}
if (port != null) {
var portPropoerty = Property.Tree.GetUnityPropertyForPath(Property.UnityPropertyPath);
if (portPropoerty == null) {
SirenixEditorGUI.ErrorMessageBox("Port property missing at: " + Property.UnityPropertyPath);
return;
} else {
var labelWidth = Property.GetAttribute<LabelWidthAttribute>();
if (labelWidth != null)
GUIHelper.PushLabelWidth(labelWidth.Width);
NodeEditorGUILayout.PropertyField(portPropoerty, label == null ? GUIContent.none : label, true, GUILayout.MinWidth(30));
if (labelWidth != null)
GUIHelper.PopLabelWidth();
}
}
}
}
}
#endif

View File

@ -1,49 +0,0 @@
#if UNITY_EDITOR && ODIN_INSPECTOR
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities.Editor;
using UnityEngine;
using XNode;
namespace XNodeEditor {
public class OutputAttributeDrawer : OdinAttributeDrawer<XNode.Node.OutputAttribute> {
protected override bool CanDrawAttributeProperty(InspectorProperty property) {
Node node = property.Tree.WeakTargets[0] as Node;
return node != null;
}
protected override void DrawPropertyLayout(GUIContent label) {
Node node = Property.Tree.WeakTargets[0] as Node;
NodePort port = node.GetOutputPort(Property.Name);
if (!NodeEditor.inNodeEditor) {
if (Attribute.backingValue == XNode.Node.ShowBackingValue.Always || Attribute.backingValue == XNode.Node.ShowBackingValue.Unconnected && !port.IsConnected)
CallNextDrawer(label);
return;
}
if (Property.Tree.WeakTargets.Count > 1) {
SirenixEditorGUI.WarningMessageBox("Cannot draw ports with multiple nodes selected");
return;
}
if (port != null) {
var portPropoerty = Property.Tree.GetUnityPropertyForPath(Property.UnityPropertyPath);
if (portPropoerty == null) {
SirenixEditorGUI.ErrorMessageBox("Port property missing at: " + Property.UnityPropertyPath);
return;
} else {
var labelWidth = Property.GetAttribute<LabelWidthAttribute>();
if (labelWidth != null)
GUIHelper.PushLabelWidth(labelWidth.Width);
NodeEditorGUILayout.PropertyField(portPropoerty, label == null ? GUIContent.none : label, true, GUILayout.MinWidth(30));
if (labelWidth != null)
GUIHelper.PopLabelWidth();
}
}
}
}
}
#endif

View File

@ -0,0 +1,26 @@
#if UNITY_EDITOR && ODIN_INSPECTOR
using Sirenix.OdinInspector.Editor;
using UnityEditor;
using UnityEngine;
using XNode;
namespace XNodeEditor.Odin
{
public class SimpleNodePortDrawer<T> : OdinValueDrawer<T>
where T : NodePort
{
protected override void Initialize()
{
base.Initialize();
this.SkipWhenDrawing = !NodeEditor.isNodeEditor;
}
protected override void DrawPropertyLayout( GUIContent label )
{
if ( label != null )
EditorGUILayout.LabelField( label );
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e30f21284cedd4945ab30934cd164eee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -21,7 +21,7 @@ namespace XNodeEditor {
public readonly static Dictionary<XNode.NodePort, Vector2> portPositions = new Dictionary<XNode.NodePort, Vector2>();
#if ODIN_INSPECTOR
internal static bool inNodeEditor = false;
public static bool isNodeEditor { get; internal set; }
#endif
public virtual void OnHeaderGUI() {
@ -31,7 +31,7 @@ namespace XNodeEditor {
/// <summary> Draws standard field editors for all public fields </summary>
public virtual void OnBodyGUI() {
#if ODIN_INSPECTOR
inNodeEditor = true;
isNodeEditor = true;
#endif
// Unity specifically requires this to save/update any serial object.
@ -57,13 +57,13 @@ namespace XNodeEditor {
if (excludes.Contains(iterator.name)) continue;
NodeEditorGUILayout.PropertyField(iterator, true);
}
#endif
// Iterate through dynamic ports and draw them in the order in which they are serialized
foreach (XNode.NodePort dynamicPort in target.DynamicPorts) {
if (NodeEditorGUILayout.IsDynamicPortListPort(dynamicPort)) continue;
NodeEditorGUILayout.PortField(dynamicPort);
}
#endif
serializedObject.ApplyModifiedProperties();
@ -78,7 +78,7 @@ namespace XNodeEditor {
#endif
#if ODIN_INSPECTOR
inNodeEditor = false;
isNodeEditor = false;
#endif
}

View File

@ -26,10 +26,10 @@ namespace XNodeEditor.Internal {
get {
if (this._objectTree == null) {
try {
bool wasInEditor = NodeEditor.inNodeEditor;
NodeEditor.inNodeEditor = true;
bool wasInEditor = NodeEditor.isNodeEditor;
NodeEditor.isNodeEditor = true;
this._objectTree = PropertyTree.Create(this.serializedObject);
NodeEditor.inNodeEditor = wasInEditor;
NodeEditor.isNodeEditor = wasInEditor;
} catch (ArgumentException ex) {
Debug.Log(ex);
}