diff --git a/Editor.Extras/Drawers/CustomBuiltInDrawer.cs b/Editor.Extras/Drawers/CustomBuiltInDrawer.cs index 264e02d..d606f27 100644 --- a/Editor.Extras/Drawers/CustomBuiltInDrawer.cs +++ b/Editor.Extras/Drawers/CustomBuiltInDrawer.cs @@ -1,5 +1,6 @@ using TriInspector; using TriInspector.Drawers; +using TriInspector.Editors; using TriInspector.Elements; using TriInspector.Utilities; using TriInspectorUnityInternalBridge; @@ -24,6 +25,15 @@ namespace TriInspector.Drawers if (drawWithHandler) { + var visualElement = handler.CreatePropertyGUI(serializedProperty); + + if (visualElement != null && + TriEditor.UiElementsRoots.TryGetValue(property.PropertyTree, out var rootElement)) + { + return new TriUiToolkitPropertyElement(property, serializedProperty, + visualElement, rootElement); + } + return new TriBuiltInPropertyElement(property, serializedProperty, handler); } } diff --git a/Editor/Editors/TriEditor.cs b/Editor/Editors/TriEditor.cs index 9134ba0..5b747a8 100644 --- a/Editor/Editors/TriEditor.cs +++ b/Editor/Editors/TriEditor.cs @@ -1,11 +1,17 @@ +using System; +using System.Collections.Generic; using TriInspector.Utilities; using UnityEditor; using UnityEngine; +using UnityEngine.UIElements; namespace TriInspector.Editors { public abstract class TriEditor : Editor { + internal static readonly Dictionary UiElementsRoots + = new Dictionary(); + private TriPropertyTreeForSerializedObject _inspector; private void OnDisable() @@ -13,6 +19,11 @@ namespace TriInspector.Editors OnDisable(this, ref _inspector); } + public override VisualElement CreateInspectorGUI() + { + return CreateInspector(root => OnInspectorGUI(this, ref _inspector, root)); + } + public override void OnInspectorGUI() { OnInspectorGUI(this, ref _inspector); @@ -20,12 +31,49 @@ namespace TriInspector.Editors public static void OnDisable(Editor editor, ref TriPropertyTreeForSerializedObject inspector) { - inspector?.Dispose(); + if (inspector != null) + { + UiElementsRoots.Remove(inspector); + + inspector.Dispose(); + } + inspector = null; } + public static VisualElement CreateInspector(Action onGui) + { + var container = new VisualElement(); + var root = new VisualElement() + { + style = + { + position = Position.Absolute, + }, + }; + + container.Add(new IMGUIContainer(() => + { + const float labelExtraPadding = 2; + const float labelWidthRatio = 0.45f; + const float labelMinWidth = 120; + + var space = container.resolvedStyle.left + container.resolvedStyle.right + labelExtraPadding; + + EditorGUIUtility.hierarchyMode = false; + EditorGUIUtility.labelWidth = Mathf.Max(labelMinWidth, + container.resolvedStyle.width * labelWidthRatio - space); + + onGui?.Invoke(root); + })); + + container.Add(root); + + return container; + } + public static void OnInspectorGUI(Editor editor, - ref TriPropertyTreeForSerializedObject inspector) + ref TriPropertyTreeForSerializedObject inspector, VisualElement visualRoot = null) { var serializedObject = editor.serializedObject; @@ -54,6 +102,11 @@ namespace TriInspector.Editors inspector = new TriPropertyTreeForSerializedObject(serializedObject); } + if (visualRoot != null) + { + UiElementsRoots[inspector] = visualRoot; + } + serializedObject.UpdateIfRequiredOrScript(); inspector.Update(); diff --git a/Editor/Editors/TriScriptedImporterEditor.cs b/Editor/Editors/TriScriptedImporterEditor.cs index 1b775fa..25d6605 100644 --- a/Editor/Editors/TriScriptedImporterEditor.cs +++ b/Editor/Editors/TriScriptedImporterEditor.cs @@ -1,6 +1,7 @@ using TriInspectorUnityInternalBridge; using UnityEditor; using UnityEditor.AssetImporters; +using UnityEngine.UIElements; namespace TriInspector.Editors { @@ -17,9 +18,19 @@ namespace TriInspector.Editors base.OnDisable(); } + public override VisualElement CreateInspectorGUI() + { + return TriEditor.CreateInspector(root => OnInspectorGUI(root)); + } + public override void OnInspectorGUI() { - TriEditor.OnInspectorGUI(this, ref _inspector); + OnInspectorGUI(null); + } + + private void OnInspectorGUI(VisualElement root) + { + TriEditor.OnInspectorGUI(this, ref _inspector, root); if (extraDataType != null) { diff --git a/Editor/Elements/TriUiToolkitPropertyElemenet.cs b/Editor/Elements/TriUiToolkitPropertyElemenet.cs new file mode 100644 index 0000000..8499415 --- /dev/null +++ b/Editor/Elements/TriUiToolkitPropertyElemenet.cs @@ -0,0 +1,91 @@ +using TriInspectorUnityInternalBridge; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace TriInspector.Elements +{ + internal class TriUiToolkitPropertyElement : TriElement + { + private readonly SerializedProperty _serializedProperty; + + private readonly VisualElement _rootElement; + private readonly VisualElement _selfElement; + + private bool _heightDirty; + + public TriUiToolkitPropertyElement( + TriProperty property, + SerializedProperty serializedProperty, + VisualElement selfElement, + VisualElement rootElement) + { + _serializedProperty = serializedProperty; + _selfElement = selfElement; + _rootElement = rootElement; + + _selfElement.style.position = Position.Absolute; + } + + protected override void OnAttachToPanel() + { + base.OnAttachToPanel(); + + _rootElement.schedule.Execute(() => + { + _rootElement.Add(_selfElement); + _selfElement.Bind(_serializedProperty.serializedObject); + }); + } + + protected override void OnDetachFromPanel() + { + _rootElement.schedule.Execute(() => + { + _selfElement.Unbind(); + _rootElement.Remove(_selfElement); + }); + + base.OnDetachFromPanel(); + } + + public override bool Update() + { + var dirty = base.Update(); + + if (_heightDirty) + { + _heightDirty = false; + dirty = true; + } + + return dirty; + } + + public override float GetHeight(float width) + { + var height = _selfElement.resolvedStyle.height; + + if (float.IsNaN(height)) + { + _heightDirty = true; + return 0f; + } + + return height; + } + + public override void OnGUI(Rect position) + { + if (Event.current.type == EventType.Repaint) + { + var pos = GUIClipProxy.UnClip(position.position); + + _selfElement.style.width = position.width; + _selfElement.style.left = pos.x; + _selfElement.style.top = pos.y; + } + } + } +} \ No newline at end of file diff --git a/Editor/Elements/TriUiToolkitPropertyElemenet.cs.meta b/Editor/Elements/TriUiToolkitPropertyElemenet.cs.meta new file mode 100644 index 0000000..a43f1c8 --- /dev/null +++ b/Editor/Elements/TriUiToolkitPropertyElemenet.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 535ce5f65f424a8c9e83943eda845fc6 +timeCreated: 1690621289 \ No newline at end of file diff --git a/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs b/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs new file mode 100644 index 0000000..bbd82ad --- /dev/null +++ b/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs @@ -0,0 +1,26 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace TriInspectorUnityInternalBridge +{ + internal static class GUIClipProxy + { + private static Func _guiClipUnClipVector2; + + [InitializeOnLoadMethod] + private static void Setup() + { + var imGuiModuleAssembly = typeof(GUI).Assembly; + var guiClipType = imGuiModuleAssembly.GetType("UnityEngine.GUIClip", throwOnError: true); + + _guiClipUnClipVector2 = (Func) Delegate.CreateDelegate(typeof(Func), + guiClipType.GetMethod("Unclip", new[] {typeof(Vector2)})); + } + + public static Vector2 UnClip(Vector2 pos) + { + return _guiClipUnClipVector2.Invoke(pos); + } + } +} \ No newline at end of file diff --git a/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs.meta b/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs.meta new file mode 100644 index 0000000..abede67 --- /dev/null +++ b/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e573403f6f844648ab1dc4013c8c4856 +timeCreated: 1690734495 \ No newline at end of file diff --git a/Unity.InternalAPIEditorBridge.012/ScriptAttributeUtilityProxy.cs b/Unity.InternalAPIEditorBridge.012/ScriptAttributeUtilityProxy.cs index c109266..8760575 100644 --- a/Unity.InternalAPIEditorBridge.012/ScriptAttributeUtilityProxy.cs +++ b/Unity.InternalAPIEditorBridge.012/ScriptAttributeUtilityProxy.cs @@ -1,5 +1,6 @@ using UnityEditor; using UnityEngine; +using UnityEngine.UIElements; namespace TriInspectorUnityInternalBridge { @@ -24,6 +25,11 @@ namespace TriInspectorUnityInternalBridge // ReSharper disable once InconsistentNaming public bool hasPropertyDrawer => _handler.hasPropertyDrawer; + public VisualElement CreatePropertyGUI(SerializedProperty property) + { + return _handler.propertyDrawer?.CreatePropertyGUI(property); + } + public float GetHeight(SerializedProperty property, GUIContent label, bool includeChildren) { return _handler.GetHeight(property, label, includeChildren);