Integration with Odin Inspector and Validator

This commit is contained in:
VladV 2022-05-21 11:49:12 +03:00
parent b258813852
commit 892cfdf07d
28 changed files with 439 additions and 300 deletions

View File

@ -1,40 +0,0 @@
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<T> : OdinAttributeDrawer<DrawWithTriInspectorAttribute, T>, IDisposable
{
private TriPropertyTreeForOdin<T> _propertyTree;
protected override void Initialize()
{
base.Initialize();
_propertyTree = new TriPropertyTreeForOdin<T>(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--;
}
}
}
}

View File

@ -0,0 +1,69 @@
using System;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities.Editor;
using TriInspector.Utilities;
using UnityEngine;
namespace TriInspector.Editor.Integrations.Odin
{
[DrawerPriority(0.0, 10000.0, 1.0)]
public class OdinFieldDrawer<T> : OdinAttributeDrawer<DrawWithTriInspectorAttribute, T>, IDisposable
{
private TriPropertyTree _propertyTree;
public override bool CanDrawTypeFilter(Type type)
{
if (typeof(UnityEngine.Object).IsAssignableFrom(type))
{
return false;
}
return true;
}
protected override bool CanDrawAttributeValueProperty(InspectorProperty property)
{
if (property.IsTreeRoot)
{
return false;
}
return true;
}
protected override void Initialize()
{
base.Initialize();
_propertyTree = new TriPropertyTreeForOdin<T>(ValueEntry);
_propertyTree.Initialize(TriEditorMode.None);
}
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)
{
using (TriGuiHelper.PushIndentLevel())
{
_propertyTree.Update();
if (_propertyTree.ValidationRequired)
{
_propertyTree.RunValidation();
}
_propertyTree.Draw();
}
}
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using Sirenix.OdinInspector.Editor;
using Sirenix.OdinInspector.Editor.Validation;
using TriInspector.Editor.Integrations.Odin;
[assembly: RegisterValidator(typeof(OdinFieldValidator<>))]
namespace TriInspector.Editor.Integrations.Odin
{
public class OdinFieldValidator<T> : AttributeValidator<DrawWithTriInspectorAttribute, T>, IDisposable
{
private TriPropertyTreeForOdin<T> _propertyTree;
public override RevalidationCriteria RevalidationCriteria { get; }
= RevalidationCriteria.OnValueChangeOrChildValueChange;
public override bool CanValidateProperty(InspectorProperty property)
{
if (typeof(UnityEngine.Object).IsAssignableFrom(property.Info.TypeOfValue))
{
return false;
}
if (property.IsTreeRoot)
{
return false;
}
return true;
}
protected override void Initialize()
{
_propertyTree = new TriPropertyTreeForOdin<T>(ValueEntry);
_propertyTree.Initialize(TriEditorMode.None);
}
public void Dispose()
{
_propertyTree.Dispose();
}
protected override void Validate(ValidationResult result)
{
_propertyTree.Update();
_propertyTree.RunValidation();
_propertyTree.CopyValidationResultsTo(result);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 50b3a32d5da945fbbdf9a981a9de5f86
timeCreated: 1653119957

View File

@ -0,0 +1,54 @@
using System;
using Sirenix.OdinInspector.Editor;
using UnityEngine;
namespace TriInspector.Editor.Integrations.Odin
{
[DrawerPriority(0.0, 10000.0, 1.0)]
public class OdinObjectDrawer<T> : OdinAttributeDrawer<DrawWithTriInspectorAttribute, T>, IDisposable
where T : UnityEngine.Object
{
private TriPropertyTree _propertyTree;
protected override bool CanDrawAttributeValueProperty(InspectorProperty property)
{
if (!property.IsTreeRoot)
{
return false;
}
if (property.Tree.UnitySerializedObject == null)
{
return false;
}
return true;
}
protected override void Initialize()
{
base.Initialize();
var serializedObject = Property.Tree.UnitySerializedObject;
_propertyTree = new TriPropertyTreeForSerializedObject(serializedObject);
_propertyTree.Initialize(TriEditorMode.None);
}
public void Dispose()
{
_propertyTree?.Dispose();
}
protected override void DrawPropertyLayout(GUIContent label)
{
_propertyTree.Update();
if (_propertyTree.ValidationRequired)
{
_propertyTree.RunValidation();
}
_propertyTree.Draw();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6a211e55ec804aa4b8554563e98d9b04
timeCreated: 1653129453

View File

@ -0,0 +1,52 @@
using System;
using Sirenix.OdinInspector.Editor;
using Sirenix.OdinInspector.Editor.Validation;
using TriInspector.Editor.Integrations.Odin;
using UnityEditor;
[assembly: RegisterValidator(typeof(OdinObjectValidator<>))]
namespace TriInspector.Editor.Integrations.Odin
{
public class OdinObjectValidator<T> : AttributeValidator<DrawWithTriInspectorAttribute, T>, IDisposable
where T : UnityEngine.Object
{
private TriPropertyTreeForSerializedObject _propertyTree;
private SerializedObject _serializedObject;
public override RevalidationCriteria RevalidationCriteria { get; }
= RevalidationCriteria.OnValueChangeOrChildValueChange;
public override bool CanValidateProperty(InspectorProperty property)
{
if (!property.IsTreeRoot)
{
return false;
}
return true;
}
protected override void Initialize()
{
_serializedObject = new SerializedObject(ValueEntry.SmartValue);
_propertyTree = new TriPropertyTreeForSerializedObject(_serializedObject);
_propertyTree.Initialize(TriEditorMode.None);
}
public void Dispose()
{
_propertyTree.Dispose();
_serializedObject.Dispose();
}
protected override void Validate(ValidationResult result)
{
_serializedObject.Update();
_propertyTree.Update();
_propertyTree.RunValidation();
_propertyTree.CopyValidationResultsTo(result);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bbb0d53e419644038a32323fb3083fb3
timeCreated: 1653123315

View File

@ -0,0 +1,33 @@
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor.Validation;
namespace TriInspector.Editor.Integrations.Odin
{
internal static class TriOdinExtensions
{
public static void CopyValidationResultsTo(this TriPropertyTree tree, ValidationResult result)
{
tree.EnumerateValidationResults((property, triResult) => result.Add(triResult));
}
private static void Add(this ValidationResult result, TriValidationResult src)
{
var severity = src.GetOdinValidatorSeverity();
result.Add(severity, src.Message);
}
private static ValidatorSeverity GetOdinValidatorSeverity(this TriValidationResult result)
{
switch (result.MessageType)
{
case TriMessageType.Error:
return ValidatorSeverity.Error;
case TriMessageType.Warning:
return ValidatorSeverity.Warning;
}
return ValidatorSeverity.Ignore;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c13b27eaa04b477db49de9a0582608b5
timeCreated: 1653124004

View File

@ -1,41 +1,36 @@
using System; using System.Linq;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector.Editor; using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor; using Sirenix.Utilities.Editor;
using TriInspector.Elements;
using UnityEditor; using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object; using Object = UnityEngine.Object;
namespace TriInspector.Editor.Integrations.Odin namespace TriInspector.Editor.Integrations.Odin
{ {
public class TriPropertyTreeForOdin<T> : ITriPropertyParent, ITriPropertyTree public class TriPropertyTreeForOdin<T> : TriPropertyTree
{ {
private readonly IPropertyValueEntry<T> _odinValueEntry; private readonly IPropertyValueEntry<T> _odinValueEntry;
private readonly InspectorProperty _odinProperty; private readonly InspectorProperty _odinProperty;
private readonly IReadOnlyList<TriProperty> _triProperties;
private readonly TriInspectorElement _triInspectorElement;
private readonly SerializedProperty _serializedProperty; private readonly SerializedProperty _serializedProperty;
private bool _validationRequired;
public TriPropertyTreeForOdin(IPropertyValueEntry<T> odinValueEntry) public TriPropertyTreeForOdin(IPropertyValueEntry<T> odinValueEntry)
{ {
_odinValueEntry = odinValueEntry; _odinValueEntry = odinValueEntry;
_odinProperty = odinValueEntry.Property; _odinProperty = odinValueEntry.Property;
_serializedProperty = _odinProperty.Tree.GetUnityPropertyForPath(_odinProperty.Path, out _);
TargetObjectType = _odinProperty.Tree.TargetType; TargetObjectType = _odinProperty.Tree.TargetType;
TargetsCount = _odinProperty.Tree.WeakTargets.Count; TargetsCount = _odinProperty.Tree.WeakTargets.Count;
TargetIsPersistent = _odinProperty.Tree.WeakTargets[0] is Object obj && TargetIsPersistent = _odinProperty.Tree.WeakTargets[0] is Object obj &&
obj != null && EditorUtility.IsPersistent(obj); obj != null && EditorUtility.IsPersistent(obj);
_serializedProperty = _odinProperty.Tree.GetUnityPropertyForPath(_odinProperty.Path, out _); UpdateEmittedScriptableObject();
UpdateAfterValueModification(); _serializedProperty.serializedObject.SetIsDifferentCacheDirty();
_serializedProperty.serializedObject.Update();
_triProperties = TriTypeDefinition.GetCached(odinValueEntry.TypeOfValue) _odinProperty.Update();
Properties = TriTypeDefinition.GetCached(odinValueEntry.TypeOfValue)
.Properties .Properties
.Select((propertyDefinition, index) => .Select((propertyDefinition, index) =>
{ {
@ -43,49 +38,22 @@ namespace TriInspector.Editor.Integrations.Odin
return new TriProperty(this, this, propertyDefinition, index, serializedProperty); return new TriProperty(this, this, propertyDefinition, index, serializedProperty);
}) })
.ToList(); .ToList();
_triInspectorElement = new TriInspectorElement(odinValueEntry.TypeOfValue, _triProperties);
_triInspectorElement.AttachInternal();
_triProperties.ForEach(it => it.Update());
_triProperties.ForEach(it => it.RunValidation());
} }
public void Draw() public override void Update()
{ {
UpdateEmittedScriptableObject(); UpdateEmittedScriptableObject();
_triProperties.ForEach(it => it.Update());
if (_validationRequired) base.Update();
{
_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 override void ForceCreateUndoGroup()
public int TargetsCount { get; }
public bool TargetIsPersistent { get; }
public void Dispose()
{
_triInspectorElement?.DetachInternal();
}
public void ForceCreateUndoGroup()
{ {
_odinProperty.RecordForUndo(forceCompleteObjectUndo: true); _odinProperty.RecordForUndo(forceCompleteObjectUndo: true);
Undo.FlushUndoRecordObjects(); Undo.FlushUndoRecordObjects();
} }
public void PrepareForValueModification() public override void PrepareForValueModification()
{ {
var dirty = false; var dirty = false;
dirty |= _odinValueEntry.ApplyChanges(); dirty |= _odinValueEntry.ApplyChanges();
@ -94,12 +62,12 @@ namespace TriInspector.Editor.Integrations.Odin
if (dirty) if (dirty)
{ {
_validationRequired = true; RequestValidation();
GUIHelper.RequestRepaint(); RequestRepaint();
} }
} }
public void UpdateAfterValueModification() public override void UpdateAfterValueModification()
{ {
UpdateEmittedScriptableObject(); UpdateEmittedScriptableObject();
@ -109,21 +77,25 @@ namespace TriInspector.Editor.Integrations.Odin
_odinProperty.Update(); _odinProperty.Update();
} }
public void RequestRepaint() public override void RequestRepaint()
{ {
base.RequestRepaint();
GUIHelper.RequestRepaint(); GUIHelper.RequestRepaint();
} }
public object GetValue(int targetIndex) public override object GetValue(int targetIndex)
{ {
return _odinValueEntry.Values[targetIndex]; return _odinValueEntry.Values[targetIndex];
} }
public void NotifyValueChanged(TriProperty property) public override void NotifyValueChanged(TriProperty property)
{ {
ApplyEmittedScriptableObject(); ApplyEmittedScriptableObject();
_odinValueEntry.Values.ForceMarkDirty(); _odinValueEntry.Values.ForceMarkDirty();
RequestValidation();
} }
private void UpdateEmittedScriptableObject() private void UpdateEmittedScriptableObject()

View File

@ -1,11 +0,0 @@
using UnityEditor;
namespace TriInspector.Editors
{
[CanEditMultipleObjects]
[CustomEditor(typeof(TriMonoBehaviour), true, isFallback = true)]
internal sealed class TriMonoBehaviourEditor : TriEditor
{
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 54df0926814e4714b27ffbe0191516f5
timeCreated: 1652774156

View File

@ -1,10 +0,0 @@
using UnityEditor;
namespace TriInspector.Editors
{
[CanEditMultipleObjects]
[CustomEditor(typeof(TriScriptableObject), true, isFallback = true)]
internal sealed class TriScriptableObjectEditor : TriEditor
{
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: a26587373eeb4f0fb8f99540b0ac352d
timeCreated: 1652774174

View File

@ -9,7 +9,7 @@ namespace TriInspector
{ {
private static readonly Stack<Editor> EditorStack = new Stack<Editor>(); private static readonly Stack<Editor> EditorStack = new Stack<Editor>();
private TriPropertyTree _inspector; private TriPropertyTreeForSerializedObject _inspector;
private TriEditorMode _editorMode; private TriEditorMode _editorMode;
@ -39,7 +39,14 @@ namespace TriInspector
return; return;
} }
_inspector = TriPropertyTree.Create(serializedObject, _editorMode); if (serializedObject.targetObject == null)
{
EditorGUILayout.HelpBox("Script is missing", MessageType.Warning);
return;
}
_inspector = new TriPropertyTreeForSerializedObject(serializedObject);
_inspector.Initialize(_editorMode);
} }
serializedObject.UpdateIfRequiredOrScript(); serializedObject.UpdateIfRequiredOrScript();
@ -59,8 +66,6 @@ namespace TriInspector
{ {
if (_inspector.ValidationRequired) if (_inspector.ValidationRequired)
{ {
_inspector.ValidationRequired = false;
_inspector.RunValidation(); _inspector.RunValidation();
} }
} }
@ -73,7 +78,7 @@ namespace TriInspector
Profiler.BeginSample("TriInspector.DoLayout()"); Profiler.BeginSample("TriInspector.DoLayout()");
try try
{ {
_inspector.DoLayout(); _inspector.Draw();
} }
finally finally
{ {
@ -88,8 +93,6 @@ namespace TriInspector
if (_inspector.RepaintRequired) if (_inspector.RepaintRequired)
{ {
_inspector.RepaintRequired = false;
Repaint(); Repaint();
} }
} }

View File

@ -27,7 +27,7 @@ namespace TriInspector
private string _isExpandedPrefsKey; private string _isExpandedPrefsKey;
internal TriProperty( internal TriProperty(
ITriPropertyTree propertyTree, TriPropertyTree propertyTree,
ITriPropertyParent parent, ITriPropertyParent parent,
TriPropertyDefinition definition, TriPropertyDefinition definition,
int propertyIndex, int propertyIndex,
@ -219,7 +219,7 @@ namespace TriInspector
: throw new InvalidOperationException("Cannot read ArrayElementProperties for " + PropertyType); : throw new InvalidOperationException("Cannot read ArrayElementProperties for " + PropertyType);
[PublicAPI] [PublicAPI]
public ITriPropertyTree PropertyTree { get; } public TriPropertyTree PropertyTree { get; }
[PublicAPI] [PublicAPI]
[CanBeNull] [CanBeNull]
@ -388,6 +388,25 @@ namespace TriInspector
} }
} }
internal void EnumerateValidationResults(Action<TriProperty, TriValidationResult> call)
{
if (_validationResults != null)
{
foreach (var result in _validationResults)
{
call.Invoke(this, result);
}
}
if (_childrenProperties != null)
{
foreach (var childrenProperty in _childrenProperties)
{
childrenProperty.EnumerateValidationResults(call);
}
}
}
[PublicAPI] [PublicAPI]
public bool TryGetSerializedProperty(out SerializedProperty serializedProperty) public bool TryGetSerializedProperty(out SerializedProperty serializedProperty)
{ {

View File

@ -1,34 +1,29 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using TriInspector.Elements; using TriInspector.Elements;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using Object = UnityEngine.Object;
namespace TriInspector namespace TriInspector
{ {
public sealed class TriPropertyTree : ITriPropertyParent, ITriPropertyTree public abstract class TriPropertyTree : ITriPropertyParent
{ {
private readonly TriEditorMode _mode; private TriInspectorElement _inspectorElement;
private readonly TriInspectorElement _inspectorElement; private TriEditorMode _mode;
private TriPropertyTree([NotNull] SerializedObject serializedObject, TriEditorMode mode) public IReadOnlyList<TriProperty> Properties { get; protected set; }
public bool IsInlineEditor => (_mode & TriEditorMode.InlineEditor) != 0;
public Type TargetObjectType { get; protected set; }
public int TargetsCount { get; protected set; }
public bool TargetIsPersistent { get; protected set; }
public bool ValidationRequired { get; private set; }
public bool RepaintRequired { get; private set; }
public void Initialize(TriEditorMode mode)
{ {
SerializedObject = serializedObject ?? throw new ArgumentNullException(nameof(serializedObject));
TargetObjects = serializedObject.targetObjects;
TargetObjectType = TargetObjects[0].GetType();
Properties = TriTypeDefinition.GetCached(TargetObjectType)
.Properties
.Select((propertyDefinition, index) =>
{
var serializedProperty = serializedObject.FindProperty(propertyDefinition.Name);
return new TriProperty(this, this, propertyDefinition, index, serializedProperty);
})
.ToList();
_mode = mode; _mode = mode;
_inspectorElement = new TriInspectorElement(TargetObjectType, Properties); _inspectorElement = new TriInspectorElement(TargetObjectType, Properties);
_inspectorElement.AttachInternal(); _inspectorElement.AttachInternal();
@ -37,37 +32,7 @@ namespace TriInspector
RunValidation(); RunValidation();
} }
[PublicAPI] public virtual void Dispose()
public IReadOnlyList<TriProperty> Properties { get; }
[PublicAPI]
public Object[] TargetObjects { get; }
[PublicAPI]
public Type TargetObjectType { get; }
[PublicAPI]
public int TargetsCount => TargetObjects.Length;
private SerializedObject SerializedObject { get; }
public bool IsInlineEditor => (_mode & TriEditorMode.InlineEditor) != 0;
public bool TargetIsPersistent => TargetObjects[0] is var targetObject &&
targetObject != null && !EditorUtility.IsPersistent(targetObject);
internal bool RepaintRequired { get; set; }
internal bool ValidationRequired { get; set; }
object ITriPropertyParent.GetValue(int targetIndex) => TargetObjects[targetIndex];
internal static TriPropertyTree Create(SerializedObject scriptableObject,
TriEditorMode mode = TriEditorMode.None)
{
return new TriPropertyTree(scriptableObject, mode);
}
public void Dispose()
{ {
if (!_inspectorElement.IsAttached) if (!_inspectorElement.IsAttached)
{ {
@ -77,7 +42,7 @@ namespace TriInspector
_inspectorElement.DetachInternal(); _inspectorElement.DetachInternal();
} }
internal void Update() public virtual void Update()
{ {
foreach (var property in Properties) foreach (var property in Properties)
{ {
@ -85,8 +50,10 @@ namespace TriInspector
} }
} }
internal void RunValidation() public void RunValidation()
{ {
ValidationRequired = false;
foreach (var property in Properties) foreach (var property in Properties)
{ {
property.RunValidation(); property.RunValidation();
@ -95,8 +62,10 @@ namespace TriInspector
RequestRepaint(); RequestRepaint();
} }
internal void DoLayout() public void Draw()
{ {
RepaintRequired = false;
_inspectorElement.Update(); _inspectorElement.Update();
var width = EditorGUIUtility.currentViewWidth; var width = EditorGUIUtility.currentViewWidth;
var height = _inspectorElement.GetHeight(width); var height = _inspectorElement.GetHeight(width);
@ -104,38 +73,15 @@ namespace TriInspector
_inspectorElement.OnGUI(rect); _inspectorElement.OnGUI(rect);
} }
public void ForceCreateUndoGroup() public void EnumerateValidationResults(Action<TriProperty, TriValidationResult> call)
{ {
Undo.RegisterCompleteObjectUndo(TargetObjects, "Inspector"); foreach (var triProperty in Properties)
Undo.FlushUndoRecordObjects();
}
public void PrepareForValueModification()
{
if (SerializedObject.ApplyModifiedProperties())
{ {
RequestValidation(); triProperty.EnumerateValidationResults(call);
RequestRepaint();
} }
} }
public void UpdateAfterValueModification() public virtual void RequestRepaint()
{
SerializedObject.SetIsDifferentCacheDirty();
SerializedObject.Update();
}
public void NotifyValueChanged(TriProperty property)
{
foreach (var targetObject in TargetObjects)
{
EditorUtility.SetDirty(targetObject);
}
RequestValidation();
}
public void RequestRepaint()
{ {
RepaintRequired = true; RepaintRequired = true;
} }
@ -143,19 +89,15 @@ namespace TriInspector
public void RequestValidation() public void RequestValidation()
{ {
ValidationRequired = true; ValidationRequired = true;
RequestRepaint();
} }
}
public interface ITriPropertyTree : IDisposable public abstract object GetValue(int targetIndex);
{ public abstract void NotifyValueChanged(TriProperty property);
Type TargetObjectType { get; } public abstract void ForceCreateUndoGroup();
int TargetsCount { get; } public abstract void PrepareForValueModification();
bool TargetIsPersistent { get; } public abstract void UpdateAfterValueModification();
void ForceCreateUndoGroup();
void PrepareForValueModification();
void UpdateAfterValueModification();
void RequestRepaint();
} }
[Flags] [Flags]

View File

@ -1,3 +1,3 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 468b264c3e164c0681760c3d98451466 guid: 9bb1d443163b4a26908eb26ba297c1d6
timeCreated: 1638857169 timeCreated: 1653126491

View File

@ -0,0 +1,67 @@
using System;
using System.Linq;
using JetBrains.Annotations;
using UnityEditor;
namespace TriInspector
{
public sealed class TriPropertyTreeForSerializedObject : TriPropertyTree
{
private readonly SerializedObject _serializedObject;
public TriPropertyTreeForSerializedObject([NotNull] SerializedObject serializedObject)
{
_serializedObject = serializedObject ?? throw new ArgumentNullException(nameof(serializedObject));
TargetObjectType = _serializedObject.targetObject.GetType();
TargetsCount = _serializedObject.targetObjects.Length;
TargetIsPersistent = _serializedObject.targetObject is var targetObject &&
targetObject != null && !EditorUtility.IsPersistent(targetObject);
Properties = TriTypeDefinition.GetCached(TargetObjectType)
.Properties
.Select((propertyDefinition, index) =>
{
var serializedProperty = serializedObject.FindProperty(propertyDefinition.Name);
return new TriProperty(this, this, propertyDefinition, index, serializedProperty);
})
.ToList();
}
public override object GetValue(int targetIndex)
{
return _serializedObject.targetObjects[targetIndex];
}
public override void ForceCreateUndoGroup()
{
Undo.RegisterCompleteObjectUndo(_serializedObject.targetObjects, "Inspector");
Undo.FlushUndoRecordObjects();
}
public override void PrepareForValueModification()
{
if (_serializedObject.ApplyModifiedProperties())
{
RequestValidation();
RequestRepaint();
}
}
public override void UpdateAfterValueModification()
{
_serializedObject.SetIsDifferentCacheDirty();
_serializedObject.Update();
}
public override void NotifyValueChanged(TriProperty property)
{
foreach (var targetObject in _serializedObject.targetObjects)
{
EditorUtility.SetDirty(targetObject);
}
RequestValidation();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 468b264c3e164c0681760c3d98451466
timeCreated: 1638857169

View File

@ -20,6 +20,7 @@ _Advanced inspector attributes for Unity_
- [Property Processors](#Property-Processors) - [Property Processors](#Property-Processors)
- [Integrations](#Integrations) - [Integrations](#Integrations)
- [Odin Inspector](#Odin-Inspector) - [Odin Inspector](#Odin-Inspector)
- [Odin Validator](#Odin-Validator)
- [License](#License) - [License](#License)
## How to Install ## How to Install
@ -644,65 +645,16 @@ Tri Inspector is able to work in compatibility mode with Odin Inspector.
In this mode, the primary interface will be drawn by the Odin Inspector. However, In this mode, the primary interface will be drawn by the Odin Inspector. However,
parts of the interface can be rendered by the Tri Inspector. parts of the interface can be rendered by the Tri Inspector.
In order for the interface to be rendered by Tri instead of Odin, it is necessary to: In order for the interface to be rendered by Tri instead of Odin,
- Use TriMonoBehaviour instead of MonoBehaviour it is necessary to mark classes with `[DrawWithTriInspector]` attribute.
- Use TriScriptableObject instead of ScriptableObject
- Mark serializable classes with DrawWithTriInspector
```csharp ### Odin Validator
public class ThisBehaviourDrawnByOdin : MonoBehaviour
{
[Sirenix.OdinInspector.InfoBox("Will be drawn by Odin Inspector as usual")]
[Sirenix.OdinInspector.BoxGroup("box", LabelText = "Box Group")]
public Texture tex;
[Sirenix.OdinInspector.InfoBox("Will be drawn by Odin Inspector as usual")] Tri Inspector is integrated with the Odin Validator
public ThisClassDrawnByOdin odin; so all validation results from Tri attributes will be shown
in the Odin Validator window.
[Sirenix.OdinInspector.InfoBox("This class marked with [DrawWithTriInspector] " + ![Odin-Validator-Integration](https://user-images.githubusercontent.com/26966368/169645537-d8f0b50f-46af-4804-95e8-337ff3b5ae83.png)
"so will be drawn by Tri Inspector")]
public ThisClassDrawnByTri tri;
}
[DeclareBoxGroup("box", Title = "Box Group")]
public class ThisBehaviourDrawnByTri : TriMonoBehaviour
{
[TriInspector.InfoBox("Parent class inherits from TriMonoBehaviour " +
"so all fields will be drawn by Tri Inspector")]
[TriInspector.Group("box")]
public Texture tex;
[TriInspector.InfoBox("It is impossible to draw Odin inside Tri, " +
"so this field will be drawn by Tri too")]
public ThisClassDrawnByOdin wrong;
[TriInspector.InfoBox("Will be drawn by Tri Inspector too")]
// This field drawn by Tri Inspector
public ThisClassDrawnByTri tri;
}
[Serializable]
public class ThisClassDrawnByOdin
{
[Sirenix.OdinInspector.LabelText("Float Field")]
public float f;
[Sirenix.OdinInspector.ListDrawerSettings(Expanded = true)]
public List<Material> materials;
}
[Serializable, DrawWithTriInspector]
public class ThisClassDrawnByTri
{
[TriInspector.LabelText("Float Field")]
public float f;
[TriInspector.ListDrawerSettings(AlwaysExpanded = true)]
public List<Material> materials;
}
```
![Odin-Inspector-Integration](https://user-images.githubusercontent.com/26966368/169118626-dc5e5f10-2274-4232-967b-2811fb7fd34b.png)
## License ## License

View File

@ -1,8 +0,0 @@
using UnityEngine;
namespace TriInspector
{
public abstract class TriMonoBehaviour : MonoBehaviour
{
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: f57eec47cca7485680d88d6daf43db8d
timeCreated: 1652774059

View File

@ -1,8 +0,0 @@
using UnityEngine;
namespace TriInspector
{
public abstract class TriScriptableObject : ScriptableObject
{
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: a07f45c37367452280cda2001e97816e
timeCreated: 1652774082

View File

@ -2,7 +2,7 @@
"name": "com.codewriter.triinspector", "name": "com.codewriter.triinspector",
"displayName": "Tri Inspector", "displayName": "Tri Inspector",
"description": "Better inspector and validator for Unity", "description": "Better inspector and validator for Unity",
"version": "1.0.1", "version": "1.0.2",
"unity": "2020.3", "unity": "2020.3",
"author": "CodeWriter (https://github.com/orgs/codewriter-packages)", "author": "CodeWriter (https://github.com/orgs/codewriter-packages)",
"homepage": "https://github.com/codewriter-packages/Tri-Inspector#readme", "homepage": "https://github.com/codewriter-packages/Tri-Inspector#readme",