diff --git a/Scripts/Editor/Drawers/Odin/AsDynamicPortAttributes.cs b/Scripts/Editor/Drawers/Odin/AsDynamicPortAttributes.cs index 5f9de23..1bd3b43 100644 --- a/Scripts/Editor/Drawers/Odin/AsDynamicPortAttributes.cs +++ b/Scripts/Editor/Drawers/Odin/AsDynamicPortAttributes.cs @@ -10,18 +10,17 @@ namespace XNodeEditor.Odin { internal abstract class AsDynamicPortAtribute : System.Attribute { - internal string fieldName { get; set; } - internal int index { get; set; } - internal Node Node { get; set; } + public string FieldName { get; set; } + public Node Node { get; set; } - internal ConnectionType connectionType { get; set; } - internal ShowBackingValue backingValue { get; set; } + public bool InList { get; set; } + public ShowBackingValue BackingValue { get; set; } - internal NodePort Port + public NodePort Port { get { - return Node.GetPort( $"{fieldName} {index}" ); + return Node.GetPort( FieldName ); } } } @@ -31,19 +30,31 @@ namespace XNodeEditor.Odin internal struct AsDynamicPortScope : IDisposable { - public AsDynamicPortScope( NodePort port ) + public AsDynamicPortScope( NodePort port, bool inList ) { EditorGUILayout.BeginVertical(); var rect = GUILayoutUtility.GetRect( 0f, float.MaxValue, 0f, 0f, GUI.skin.label, GUILayout.ExpandWidth( true ) ); - if ( NodeEditor.isNodeEditor ) + if ( port != null && NodeEditor.isNodeEditor ) { if ( port.IsInput ) { - NodeEditorGUILayout.PortField( new Vector2( rect.xMin - 42, rect.center.y ), port ); + Vector2 offset; + if ( inList ) + offset = new Vector2( -42, 0 ); + else + offset = new Vector2( -18, 0 ); + + NodeEditorGUILayout.PortField( new Vector2( rect.xMin, rect.center.y ) + offset, port ); } else { - NodeEditorGUILayout.PortField( new Vector2( rect.xMax + 21, rect.center.y ), port ); + Vector2 offset; + if ( inList ) + offset = new Vector2( 21, 0 ); + else + offset = new Vector2( 0, 0 ); + + NodeEditorGUILayout.PortField( new Vector2( rect.xMax, rect.center.y ) + offset, port ); } } @@ -67,7 +78,7 @@ namespace XNodeEditor.Odin if ( Attribute.Port == null ) return; - using ( new AsDynamicPortScope( Attribute.Port ) ) + using ( new AsDynamicPortScope( Attribute.Port, Attribute.InList ) ) CallNextDrawer( label ); } } @@ -83,9 +94,9 @@ namespace XNodeEditor.Odin return; if ( Event.current.type == EventType.Layout ) - drawData = Attribute.backingValue == ShowBackingValue.Always || Attribute.backingValue == ShowBackingValue.Unconnected && !Attribute.Port.IsConnected; + drawData = Attribute.BackingValue == ShowBackingValue.Always || Attribute.BackingValue == ShowBackingValue.Unconnected && !Attribute.Port.IsConnected; - using ( new AsDynamicPortScope( Attribute.Port ) ) + using ( new AsDynamicPortScope( Attribute.Port, Attribute.InList ) ) { if ( drawData ) CallNextDrawer( label ); diff --git a/Scripts/Editor/Drawers/Odin/AsStaticPortAttributes.cs b/Scripts/Editor/Drawers/Odin/AsStaticPortAttributes.cs index 686a446..69592c6 100644 --- a/Scripts/Editor/Drawers/Odin/AsStaticPortAttributes.cs +++ b/Scripts/Editor/Drawers/Odin/AsStaticPortAttributes.cs @@ -14,7 +14,7 @@ namespace XNodeEditor.Odin { EditorGUILayout.BeginVertical(); var rect = GUILayoutUtility.GetRect( 0f, float.MaxValue, 0f, 0f, GUI.skin.label, GUILayout.ExpandWidth( true ) ); - if ( NodeEditor.isNodeEditor ) + if ( port != null && NodeEditor.isNodeEditor ) { if ( port.IsInput ) { diff --git a/Scripts/Editor/Drawers/Odin/DynamicPortListBackedResolver.cs b/Scripts/Editor/Drawers/Odin/DynamicPortListBackedResolver.cs index 372b2fe..62396a1 100644 --- a/Scripts/Editor/Drawers/Odin/DynamicPortListBackedResolver.cs +++ b/Scripts/Editor/Drawers/Odin/DynamicPortListBackedResolver.cs @@ -86,12 +86,11 @@ namespace XNodeEditor.Odin { return new AsDynamicPortWithDataAtribute() { - fieldName = fieldName, - index = index, + FieldName = string.Format( "{0} {1}", fieldName, index ), + InList = true, Node = node, - connectionType = connectionType, - backingValue = backingValue + BackingValue = backingValue }; } diff --git a/Scripts/Editor/Drawers/Odin/DynamicPortListNoDataResolver.cs b/Scripts/Editor/Drawers/Odin/DynamicPortListNoDataResolver.cs index ec30682..d20ba57 100644 --- a/Scripts/Editor/Drawers/Odin/DynamicPortListNoDataResolver.cs +++ b/Scripts/Editor/Drawers/Odin/DynamicPortListNoDataResolver.cs @@ -69,12 +69,11 @@ namespace XNodeEditor { return new AsDynamicPortNoDataAtribute() { - fieldName = fieldName, - index = index, + FieldName = string.Format( "{0} {1}", fieldName, index ), + InList = true, Node = node, - connectionType = connectionType, - backingValue = backingValue + BackingValue = backingValue }; } diff --git a/Scripts/Editor/Drawers/Odin/FullyDynamicPortPropertyResolver.cs b/Scripts/Editor/Drawers/Odin/FullyDynamicPortPropertyResolver.cs new file mode 100644 index 0000000..50c2bce --- /dev/null +++ b/Scripts/Editor/Drawers/Odin/FullyDynamicPortPropertyResolver.cs @@ -0,0 +1,72 @@ +#if UNITY_EDITOR && ODIN_INSPECTOR +using Sirenix.OdinInspector.Editor; +using Sirenix.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using XNode; +using XNodeEditor.Odin; +using static XNode.Node; + +namespace XNodeEditor +{ + [ResolverPriority( -4 )] + public class FullyDynamicPortPropertyResolver : BaseMemberPropertyResolver + where T : Node + { + private List processors; + + protected override InspectorPropertyInfo[] GetPropertyInfos() + { + if ( this.processors == null ) + { + this.processors = OdinPropertyProcessorLocator.GetMemberProcessors( this.Property ); + } + + var includeSpeciallySerializedMembers = this.Property.ValueEntry.SerializationBackend != SerializationBackend.Unity; + var infos = InspectorPropertyInfoUtility.CreateMemberProperties( this.Property, typeof( T ), includeSpeciallySerializedMembers ); + + for ( int i = 0; i < this.processors.Count; i++ ) + { + ProcessedMemberPropertyResolverExtensions.ProcessingOwnerType = typeof( T ); + this.processors[i].ProcessMemberProperties( infos ); + } + + // Find ports that aren't managed by an attribute + if ( this.Property.Tree.UnitySerializedObject.targetObjects.Length == 1 ) + { + var node = Property.Tree.UnitySerializedObject.targetObject as Node; + var nodeType = typeof( T ); + + string error; + MemberInfo[] fieldsAndProperties; + nodeType.FindMember() + .IsFieldOrProperty() + .TryGetMembers( out fieldsAndProperties, out error ); + var attributedMembers = fieldsAndProperties?.Where( x => x.GetAttribute() != null || x.GetAttribute() != null ); + + foreach ( var port in node.DynamicPorts ) + { + if ( attributedMembers.Any( x => port.fieldName.StartsWith( string.Format( "{0} ", x.Name ) ) ) ) + continue; + + // value can't possibly matter here so many this "lie" is ok + infos.AddValue( port.fieldName, () => 0, value => { }, + new AsDynamicPortNoDataAtribute() + { + BackingValue = ShowBackingValue.Never, + FieldName = port.fieldName, + InList = false, + Node = node + } + ); + } + + } + + return InspectorPropertyInfoUtility.BuildPropertyGroupsAndFinalize( this.Property, typeof( T ), infos, includeSpeciallySerializedMembers ); + } + } +} +#endif \ No newline at end of file diff --git a/Scripts/Editor/Drawers/Odin/FullyDynamicPortPropertyResolver.cs.meta b/Scripts/Editor/Drawers/Odin/FullyDynamicPortPropertyResolver.cs.meta new file mode 100644 index 0000000..0b9efaf --- /dev/null +++ b/Scripts/Editor/Drawers/Odin/FullyDynamicPortPropertyResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95e515f7b1abc3440b3e1a9f324f9187 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: