Added InlineEditor attribute

This commit is contained in:
VladV 2022-01-08 20:45:11 +03:00
parent 09e2eda979
commit 2e8014ac14
9 changed files with 271 additions and 5 deletions

View File

@ -0,0 +1,190 @@
using TriInspector;
using TriInspector.Drawers;
using TriInspector.Elements;
using TriInspector.GroupDrawers;
using TriInspector.Utilities;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
[assembly: RegisterTriAttributeDrawer(typeof(InlineEditorDrawer), TriDrawerOrder.Fallback - 1000,
Target = TriTargetPropertyType.Self)]
namespace TriInspector.Drawers
{
public class InlineEditorDrawer : TriAttributeDrawer<InlineEditorAttribute>
{
public override TriElement CreateElement(TriProperty property, TriElement next)
{
if (!typeof(Object).IsAssignableFrom(property.FieldType))
{
var stack = new TriElement();
stack.AddChild(new TriInfoBoxElement($"InlineEditor valid only on Object fields",
MessageType.Error));
stack.AddChild(next);
return stack;
}
var element = new TriBoxGroupDrawer.TriBoxGroupElement(new DeclareBoxGroupAttribute(""));
element.AddChild(new ObjectReferenceFoldoutDrawerElement(property));
element.AddChild(new InlineEditorDrawerElement(property));
return element;
}
private class ObjectReferenceFoldoutDrawerElement : TriElement
{
private readonly TriProperty _property;
public ObjectReferenceFoldoutDrawerElement(TriProperty property)
{
_property = property;
}
public override float GetHeight(float width)
{
return EditorGUIUtility.singleLineHeight;
}
public override void OnGUI(Rect position)
{
var prefixRect = new Rect(position)
{
height = EditorGUIUtility.singleLineHeight,
xMax = position.xMin + EditorGUIUtility.labelWidth,
};
var pickerRect = new Rect(position)
{
height = EditorGUIUtility.singleLineHeight,
xMin = prefixRect.xMax,
};
TriGuiHelper.PushIndentLevel();
TriEditorGUI.Foldout(prefixRect, _property);
TriGuiHelper.PopIndentLevel();
EditorGUI.BeginChangeCheck();
var allowSceneObjects = _property.PropertyTree.TargetObjects[0] is var targetObject &&
targetObject != null && !EditorUtility.IsPersistent(targetObject);
var value = (Object) _property.Value;
value = EditorGUI.ObjectField(pickerRect, GUIContent.none, value,
_property.FieldType, allowSceneObjects);
if (EditorGUI.EndChangeCheck())
{
_property.SetValue(value);
}
}
}
private class InlineEditorDrawerElement : TriElement
{
private readonly TriProperty _property;
private Editor _editor;
private Rect _editorPosition;
private bool _dirty;
public InlineEditorDrawerElement(TriProperty property)
{
_property = property;
_editorPosition = Rect.zero;
}
protected override void OnDetachFromPanel()
{
if (_editor != null)
{
Object.DestroyImmediate(_editor);
}
base.OnDetachFromPanel();
}
public override bool Update()
{
if (_editor == null || _editor.target != (Object) _property.Value)
{
if (_editor != null)
{
Object.DestroyImmediate(_editor);
}
_dirty = true;
}
if (_dirty)
{
_dirty = false;
return true;
}
return false;
}
public override float GetHeight(float width)
{
if (_property.IsExpanded && !_property.IsValueMixed)
{
return _editorPosition.height;
}
return 0f;
}
public override void OnGUI(Rect position)
{
if (Event.current.type == EventType.Repaint)
{
_editorPosition = position;
}
var lastEditorRect = Rect.zero;
if (TriGuiHelper.IsEditorForObjectPushed((Object) _property.Value))
{
GUI.Label(position, "Recursive inline editors not supported");
lastEditorRect.height = EditorGUIUtility.singleLineHeight;
}
else
{
if (_editor == null)
{
_editor = Editor.CreateEditor((Object) _property.Value);
}
if (_editor != null && _property.IsExpanded && !_property.IsValueMixed)
{
TriGuiHelper.PushIndentLevel();
var indentedEditorPosition = EditorGUI.IndentedRect(_editorPosition);
TriGuiHelper.PopIndentLevel();
GUILayout.BeginArea(indentedEditorPosition);
GUILayout.BeginVertical();
_editor.OnInspectorGUI();
GUILayout.EndVertical();
lastEditorRect = GUILayoutUtility.GetLastRect();
GUILayout.EndArea();
}
else
{
if (_editor != null)
{
Object.DestroyImmediate(_editor);
}
}
}
if (Event.current.type == EventType.Repaint &&
!Mathf.Approximately(_editorPosition.height, lastEditorRect.height))
{
_editorPosition.height = lastEditorRect.height;
_dirty = true;
_property.PropertyTree.RequestRepaint();
}
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 088c34bc4fc448b4aac18ed9bf4f9bc6
timeCreated: 1641657562

View File

@ -16,7 +16,7 @@ namespace TriInspector.GroupDrawers
return new TriBoxGroupElement(attribute);
}
private class TriBoxGroupElement : TriPropertyCollectionBaseElement
public class TriBoxGroupElement : TriPropertyCollectionBaseElement
{
private const float HeaderWidth = 22;
private const float InsetTop = 4;

View File

@ -1,5 +1,6 @@
using TriInspector.Utilities;
using UnityEditor;
using UnityEngine;
using UnityEngine.Profiling;
namespace TriInspector
@ -10,15 +11,24 @@ namespace TriInspector
private void OnEnable()
{
var mode = TriEditorMode.None;
var isInlineEditor = TriGuiHelper.PushedEditorCount > 0;
if (isInlineEditor)
{
mode |= TriEditorMode.InlineEditor;
}
if (serializedObject.targetObject != null)
{
_inspector = TriPropertyTree.Create(serializedObject);
_inspector = TriPropertyTree.Create(serializedObject, mode);
}
}
private void OnDisable()
{
_inspector?.Destroy();
_inspector = null;
}
public override void OnInspectorGUI()
@ -54,6 +64,13 @@ namespace TriInspector
}
serializedObject.ApplyModifiedProperties();
if (_inspector.RepaintRequired)
{
_inspector.RepaintRequired = false;
Repaint();
}
}
}
}

View File

@ -15,6 +15,8 @@ namespace TriInspector
[PublicAPI]
public int ChildrenCount => _children.Count;
public bool IsAttached => _attached;
[PublicAPI]
public virtual bool Update()
{

View File

@ -11,9 +11,10 @@ namespace TriInspector
{
public sealed class TriPropertyTree : ITriPropertyParent
{
private readonly TriEditorMode _mode;
private readonly TriInspectorElement _inspectorElement;
private TriPropertyTree([NotNull] SerializedObject serializedObject)
private TriPropertyTree([NotNull] SerializedObject serializedObject, TriEditorMode mode)
{
SerializedObject = serializedObject ?? throw new ArgumentNullException(nameof(serializedObject));
TargetObjects = serializedObject.targetObjects;
@ -29,6 +30,7 @@ namespace TriInspector
})
.ToList();
_mode = mode;
_inspectorElement = new TriInspectorElement(this);
_inspectorElement.AttachInternal();
}
@ -47,15 +49,25 @@ namespace TriInspector
public TriPropertyTree Root { get; }
public bool IsInlineEditor => (_mode & TriEditorMode.InlineEditor) != 0;
internal bool RepaintRequired { get; set; }
object ITriPropertyParent.GetValue(int targetIndex) => TargetObjects[targetIndex];
internal static TriPropertyTree Create(SerializedObject scriptableObject)
internal static TriPropertyTree Create(SerializedObject scriptableObject,
TriEditorMode mode = TriEditorMode.None)
{
return new TriPropertyTree(scriptableObject);
return new TriPropertyTree(scriptableObject, mode);
}
internal void Destroy()
{
if (!_inspectorElement.IsAttached)
{
return;
}
_inspectorElement.DetachInternal();
}
@ -76,5 +88,17 @@ namespace TriInspector
var rect = GUILayoutUtility.GetRect(width, height);
_inspectorElement.OnGUI(rect);
}
public void RequestRepaint()
{
RepaintRequired = true;
}
}
[Flags]
public enum TriEditorMode
{
None = 0,
InlineEditor = 1 << 0,
}
}

View File

@ -18,6 +18,21 @@ namespace TriInspector.Utilities
IndentLevelStack.Clear();
}
public static int PushedEditorCount => EditorStack.Count;
public static bool IsEditorForObjectPushed(Object target)
{
foreach (var it in EditorStack)
{
if (it.editor.target == target)
{
return true;
}
}
return false;
}
public static void PushEditor(Editor editor)
{
EditorStack.Push(new EditorData

View File

@ -0,0 +1,12 @@
using System;
using System.Diagnostics;
namespace TriInspector
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property |
AttributeTargets.Class | AttributeTargets.Struct)]
[Conditional("UNITY_EDITOR")]
public sealed class InlineEditorAttribute : Attribute
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1d09104644014c71b3b0c3b472b743a5
timeCreated: 1641657539