From fc4da39d7525133e7b1906c10f9116f845b1de57 Mon Sep 17 00:00:00 2001 From: VladV Date: Wed, 18 May 2022 09:20:51 +0300 Subject: [PATCH] Add OdinInspector integration --- Editor.Integrations.meta | 8 + Editor.Integrations/Odin.meta | 3 + .../Odin/DrawWithTriInspectorDrawer.cs | 40 +++++ .../Odin/DrawWithTriInspectorDrawer.cs.meta | 3 + ...iInspector.Editor.Integrations.Odin.asmdef | 23 +++ ...ector.Editor.Integrations.Odin.asmdef.meta | 7 + .../Odin/TriPropertyTreeForOdin.cs | 161 ++++++++++++++++++ .../Odin/TriPropertyTreeForOdin.cs.meta | 3 + Editor/AssemblyInfo.cs | 3 + Editor/AssemblyInfo.cs.meta | 3 + Editor/TriProperty.cs | 2 +- Editor/TriPropertyTree.cs | 14 +- .../DrawWithTriInspectorAttribute.cs | 11 ++ .../DrawWithTriInspectorAttribute.cs.meta | 3 + 14 files changed, 278 insertions(+), 6 deletions(-) create mode 100644 Editor.Integrations.meta create mode 100644 Editor.Integrations/Odin.meta create mode 100644 Editor.Integrations/Odin/DrawWithTriInspectorDrawer.cs create mode 100644 Editor.Integrations/Odin/DrawWithTriInspectorDrawer.cs.meta create mode 100644 Editor.Integrations/Odin/TriInspector.Editor.Integrations.Odin.asmdef create mode 100644 Editor.Integrations/Odin/TriInspector.Editor.Integrations.Odin.asmdef.meta create mode 100644 Editor.Integrations/Odin/TriPropertyTreeForOdin.cs create mode 100644 Editor.Integrations/Odin/TriPropertyTreeForOdin.cs.meta create mode 100644 Editor/AssemblyInfo.cs create mode 100644 Editor/AssemblyInfo.cs.meta create mode 100644 Runtime/Attributes/DrawWithTriInspectorAttribute.cs create mode 100644 Runtime/Attributes/DrawWithTriInspectorAttribute.cs.meta diff --git a/Editor.Integrations.meta b/Editor.Integrations.meta new file mode 100644 index 0000000..601a244 --- /dev/null +++ b/Editor.Integrations.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e6b289af1e2447f40a294b9fd063474a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor.Integrations/Odin.meta b/Editor.Integrations/Odin.meta new file mode 100644 index 0000000..fa7246c --- /dev/null +++ b/Editor.Integrations/Odin.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8f456555c4d04a27a1ee0166c06cf796 +timeCreated: 1652773355 \ No newline at end of file diff --git a/Editor.Integrations/Odin/DrawWithTriInspectorDrawer.cs b/Editor.Integrations/Odin/DrawWithTriInspectorDrawer.cs new file mode 100644 index 0000000..8eb6795 --- /dev/null +++ b/Editor.Integrations/Odin/DrawWithTriInspectorDrawer.cs @@ -0,0 +1,40 @@ +using System; +using Sirenix.OdinInspector.Editor; +using Sirenix.Utilities.Editor; +using UnityEditor; +using UnityEngine; + +namespace TriInspector.Editor.Integrations.Odin +{ + [DrawerPriority(0.0, 0.0, 6000.0)] + public class DrawWithTriInspectorDrawer : OdinAttributeDrawer, IDisposable + { + private TriPropertyTreeForOdin _propertyTree; + + protected override void Initialize() + { + base.Initialize(); + + _propertyTree = new TriPropertyTreeForOdin(ValueEntry); + } + + public void Dispose() + { + _propertyTree?.Dispose(); + } + + protected override void DrawPropertyLayout(GUIContent label) + { + var propertyState = ValueEntry.Property.State; + + propertyState.Expanded = SirenixEditorGUI.Foldout(propertyState.Expanded, label); + + if (propertyState.Expanded) + { + EditorGUI.indentLevel++; + _propertyTree.Draw(); + EditorGUI.indentLevel--; + } + } + } +} \ No newline at end of file diff --git a/Editor.Integrations/Odin/DrawWithTriInspectorDrawer.cs.meta b/Editor.Integrations/Odin/DrawWithTriInspectorDrawer.cs.meta new file mode 100644 index 0000000..2efcc69 --- /dev/null +++ b/Editor.Integrations/Odin/DrawWithTriInspectorDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ee9c37a0a21643c2a7037a7a159b4355 +timeCreated: 1652773581 \ No newline at end of file diff --git a/Editor.Integrations/Odin/TriInspector.Editor.Integrations.Odin.asmdef b/Editor.Integrations/Odin/TriInspector.Editor.Integrations.Odin.asmdef new file mode 100644 index 0000000..29b10e1 --- /dev/null +++ b/Editor.Integrations/Odin/TriInspector.Editor.Integrations.Odin.asmdef @@ -0,0 +1,23 @@ +{ + "name": "TriInspector.Editor.Integrations.Odin", + "rootNamespace": "", + "references": [ + "TriInspector", + "TriInspector.Editor" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [ + "" + ], + "autoReferenced": false, + "defineConstraints": [ + "ODIN_INSPECTOR" + ], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Editor.Integrations/Odin/TriInspector.Editor.Integrations.Odin.asmdef.meta b/Editor.Integrations/Odin/TriInspector.Editor.Integrations.Odin.asmdef.meta new file mode 100644 index 0000000..7844a16 --- /dev/null +++ b/Editor.Integrations/Odin/TriInspector.Editor.Integrations.Odin.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 90456d836f7b85c45a469d1f5ee611b1 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor.Integrations/Odin/TriPropertyTreeForOdin.cs b/Editor.Integrations/Odin/TriPropertyTreeForOdin.cs new file mode 100644 index 0000000..e68159d --- /dev/null +++ b/Editor.Integrations/Odin/TriPropertyTreeForOdin.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Sirenix.OdinInspector.Editor; +using Sirenix.Utilities; +using Sirenix.Utilities.Editor; +using TriInspector.Elements; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace TriInspector.Editor.Integrations.Odin +{ + public class TriPropertyTreeForOdin : ITriPropertyParent, ITriPropertyTree + { + private readonly IPropertyValueEntry _odinValueEntry; + private readonly InspectorProperty _odinProperty; + private readonly IReadOnlyList _triProperties; + private readonly TriInspectorElement _triInspectorElement; + private readonly SerializedProperty _serializedProperty; + + private bool _validationRequired; + + public TriPropertyTreeForOdin(IPropertyValueEntry odinValueEntry) + { + _odinValueEntry = odinValueEntry; + _odinProperty = odinValueEntry.Property; + + TargetObjectType = _odinProperty.Tree.TargetType; + TargetsCount = _odinProperty.Tree.WeakTargets.Count; + TargetIsPersistent = _odinProperty.Tree.WeakTargets[0] is Object obj && + obj != null && EditorUtility.IsPersistent(obj); + + _serializedProperty = _odinProperty.Tree.GetUnityPropertyForPath(_odinProperty.Path, out _); + + UpdateAfterValueModification(); + + _triProperties = TriTypeDefinition.GetCached(odinValueEntry.TypeOfValue) + .Properties + .Select((propertyDefinition, index) => + { + var serializedProperty = _serializedProperty.FindPropertyRelative(propertyDefinition.Name); + return new TriProperty(this, this, propertyDefinition, index, serializedProperty); + }) + .ToList(); + + _triInspectorElement = new TriInspectorElement(odinValueEntry.TypeOfValue, _triProperties); + _triInspectorElement.AttachInternal(); + + _triProperties.ForEach(it => it.Update()); + _triProperties.ForEach(it => it.RunValidation()); + } + + public void Draw() + { + UpdateEmittedScriptableObject(); + _triProperties.ForEach(it => it.Update()); + + if (_validationRequired) + { + _validationRequired = false; + + _triProperties.ForEach(it => it.RunValidation()); + } + + _triInspectorElement.Update(); + var width = EditorGUIUtility.currentViewWidth; + var height = _triInspectorElement.GetHeight(width); + var rect = GUILayoutUtility.GetRect(width, height); + _triInspectorElement.OnGUI(rect); + } + + public Type TargetObjectType { get; } + public int TargetsCount { get; } + public bool TargetIsPersistent { get; } + + public void Dispose() + { + _triInspectorElement?.DetachInternal(); + } + + public void ForceCreateUndoGroup() + { + _odinProperty.RecordForUndo(forceCompleteObjectUndo: true); + Undo.FlushUndoRecordObjects(); + } + + public void PrepareForValueModification() + { + var dirty = false; + dirty |= _odinValueEntry.ApplyChanges(); + dirty |= _serializedProperty.serializedObject.ApplyModifiedProperties(); + dirty |= ApplyEmittedScriptableObject(); + + if (dirty) + { + _validationRequired = true; + GUIHelper.RequestRepaint(); + } + } + + public void UpdateAfterValueModification() + { + UpdateEmittedScriptableObject(); + + _serializedProperty.serializedObject.SetIsDifferentCacheDirty(); + _serializedProperty.serializedObject.Update(); + + _odinProperty.Update(); + } + + public void RequestRepaint() + { + GUIHelper.RequestRepaint(); + } + + public object GetValue(int targetIndex) + { + return _odinValueEntry.Values[targetIndex]; + } + + public void NotifyValueChanged(TriProperty property) + { + ApplyEmittedScriptableObject(); + + _odinValueEntry.Values.ForceMarkDirty(); + } + + private void UpdateEmittedScriptableObject() + { + if (_serializedProperty.serializedObject.targetObject is EmittedScriptableObject) + { + var targetObjects = _serializedProperty.serializedObject.targetObjects; + for (var index = 0; index < targetObjects.Length; ++index) + { + ((EmittedScriptableObject) targetObjects[index]).SetValue(_odinValueEntry.Values[index]); + } + + _serializedProperty.serializedObject.Update(); + } + } + + private bool ApplyEmittedScriptableObject() + { + var dirty = false; + + if (_serializedProperty.serializedObject.targetObject is EmittedScriptableObject) + { + dirty = _serializedProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo(); + + var targetObjects = _serializedProperty.serializedObject.targetObjects; + for (var index = 0; index < targetObjects.Length; ++index) + { + _odinValueEntry.Values[index] = ((EmittedScriptableObject) targetObjects[index]).GetValue(); + } + } + + return dirty; + } + } +} \ No newline at end of file diff --git a/Editor.Integrations/Odin/TriPropertyTreeForOdin.cs.meta b/Editor.Integrations/Odin/TriPropertyTreeForOdin.cs.meta new file mode 100644 index 0000000..c187d47 --- /dev/null +++ b/Editor.Integrations/Odin/TriPropertyTreeForOdin.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d883d32fb4d94844b172e3a08edbf2b4 +timeCreated: 1652774822 \ No newline at end of file diff --git a/Editor/AssemblyInfo.cs b/Editor/AssemblyInfo.cs new file mode 100644 index 0000000..985a429 --- /dev/null +++ b/Editor/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("TriInspector.Editor.Integrations.Odin")] \ No newline at end of file diff --git a/Editor/AssemblyInfo.cs.meta b/Editor/AssemblyInfo.cs.meta new file mode 100644 index 0000000..28fa3ee --- /dev/null +++ b/Editor/AssemblyInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 31eceb5f41944fc5a4afccb7697d3e61 +timeCreated: 1652775741 \ No newline at end of file diff --git a/Editor/TriProperty.cs b/Editor/TriProperty.cs index cd1c243..5ef7bbe 100644 --- a/Editor/TriProperty.cs +++ b/Editor/TriProperty.cs @@ -252,7 +252,7 @@ namespace TriInspector PropertyTree.PrepareForValueModification(); // record object state for undp - Undo.FlushUndoRecordObjects(); + PropertyTree.ForceCreateUndoGroup(); // set value for all targets for (var targetIndex = 0; targetIndex < PropertyTree.TargetsCount; targetIndex++) diff --git a/Editor/TriPropertyTree.cs b/Editor/TriPropertyTree.cs index 52133bc..636e17f 100644 --- a/Editor/TriPropertyTree.cs +++ b/Editor/TriPropertyTree.cs @@ -104,10 +104,10 @@ namespace TriInspector _inspectorElement.OnGUI(rect); } - public void UpdateAfterValueModification() + public void ForceCreateUndoGroup() { - SerializedObject.SetIsDifferentCacheDirty(); - SerializedObject.Update(); + Undo.RegisterCompleteObjectUndo(TargetObjects, "Inspector"); + Undo.FlushUndoRecordObjects(); } public void PrepareForValueModification() @@ -117,9 +117,12 @@ namespace TriInspector RequestValidation(); RequestRepaint(); } + } - Undo.RegisterCompleteObjectUndo(TargetObjects, "Inspector"); - Undo.FlushUndoRecordObjects(); + public void UpdateAfterValueModification() + { + SerializedObject.SetIsDifferentCacheDirty(); + SerializedObject.Update(); } public void NotifyValueChanged(TriProperty property) @@ -149,6 +152,7 @@ namespace TriInspector int TargetsCount { get; } bool TargetIsPersistent { get; } + void ForceCreateUndoGroup(); void PrepareForValueModification(); void UpdateAfterValueModification(); void RequestRepaint(); diff --git a/Runtime/Attributes/DrawWithTriInspectorAttribute.cs b/Runtime/Attributes/DrawWithTriInspectorAttribute.cs new file mode 100644 index 0000000..13a4905 --- /dev/null +++ b/Runtime/Attributes/DrawWithTriInspectorAttribute.cs @@ -0,0 +1,11 @@ +using System; +using System.Diagnostics; + +namespace TriInspector +{ + [AttributeUsage(AttributeTargets.Class)] + [Conditional("UNITY_EDITOR")] + public class DrawWithTriInspectorAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Runtime/Attributes/DrawWithTriInspectorAttribute.cs.meta b/Runtime/Attributes/DrawWithTriInspectorAttribute.cs.meta new file mode 100644 index 0000000..6290c36 --- /dev/null +++ b/Runtime/Attributes/DrawWithTriInspectorAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 33460afbb365415a9ff9d9379f0cec59 +timeCreated: 1652773384 \ No newline at end of file