Advertisement
zORg_alex

SceneView PropertyDrawer Editor

Nov 12th, 2024 (edited)
102
0
Never
3
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.45 KB | Source Code | 0 0
  1. #if UNITY_EDITOR
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Scripts.Extensions.Serialized;
  6. using UnityEditor;
  7. using UnityEngine;
  8. using UnityEngine.SceneManagement;
  9. using Object = UnityEngine.Object;
  10.  
  11. namespace Scripts.Extensions
  12. {
  13.     public static class SceneViewDrawerExtensions
  14.     {
  15.         /// <summary>
  16.         /// Depends on https://gist.github.com/douduck08/6d3e323b538a741466de00c30aa4b61f
  17.         /// </summary>
  18.         /// <typeparam name="T">Field Type</typeparam>
  19.         /// <typeparam name="TContext">Context Type for contraint</typeparam>
  20.         public abstract class Context<T, TContext>
  21.             where T : class
  22.             where TContext : Context<T, TContext>, new()
  23.         {
  24.             private static List<TContext> _subscribedEditors = new();
  25.             public static bool IsAnyEditing => _subscribedEditors.Any(ed => ed.IsEditing);
  26.             private TContext _self;
  27.             protected SerializedProperty _property;
  28.             protected T _field;
  29.             protected Object _object;
  30.             public bool IsEditing;
  31.             private float _lastGUIUpdate;
  32.  
  33.             private void Initialize(SerializedProperty property, TContext ctx)
  34.             {
  35.                 _property = property;
  36.                 _field = property.GetValue<T>();
  37.                 _object = property.serializedObject.targetObject;
  38.                 _self = ctx;
  39.             }
  40.             public static bool TrySubscribing(SerializedProperty property, out TContext ctx)
  41.             {
  42.                 try //Applying or reverting changes destroys SerializedObject and there is no way to find this out
  43.                 {
  44.                     ctx = _subscribedEditors?.FirstOrDefault(ctx => ctx._property.propertyPath == property.propertyPath);
  45.                     if (ctx != null)
  46.                     {
  47.                         ctx._field = property.GetValue<T>();
  48.                         return true;
  49.                     }
  50.                 }
  51.                 catch (Exception)
  52.                 {
  53.                     _subscribedEditors.ToList().ForEach(ed => ed.UnsubscribeEditor());
  54.                     ctx = null;
  55.                     return false;
  56.                 }
  57.                 ctx = new TContext();
  58.                 ctx.Initialize(property, ctx);
  59.                 ctx.SubscribeEditor();
  60.                 _subscribedEditors.Add(ctx);
  61.                 return true;
  62.             }
  63.             private void SubscribeEditor()
  64.             {
  65.                 SceneView.duringSceneGui += OnSceneGUIInternal;
  66.                 Selection.selectionChanged += UnsubscribeEditor;
  67.                 SceneManager.sceneUnloaded += UnsubscribeEditor;
  68.                 AssemblyReloadEvents.beforeAssemblyReload += UnsubscribeEditor;
  69.             }
  70.  
  71.             private void UnsubscribeEditor(Scene arg0) => UnsubscribeEditor();
  72.             internal void UnsubscribeEditor()
  73.             {
  74.                 SceneView.duringSceneGui -= OnSceneGUIInternal;
  75.                 Selection.selectionChanged -= UnsubscribeEditor;
  76.                 SceneManager.sceneUnloaded -= UnsubscribeEditor;
  77.                 AssemblyReloadEvents.beforeAssemblyReload -= UnsubscribeEditor;
  78.                 _subscribedEditors.Remove(_self);
  79.  
  80.                 if (IsEditing)
  81.                 {
  82.                     IsEditing = false;
  83.                     OnStopped();
  84.                 }
  85.             }
  86.  
  87.             protected virtual void OnStopped() { }
  88.  
  89.             protected void OnSceneGUIInternal(SceneView view)
  90.             {
  91.                 if (Time.time - _lastGUIUpdate > 1.5f)
  92.                 {
  93.                     UnsubscribeEditor();
  94.                     return;
  95.                 }
  96.                 OnSceneGUI();
  97.             }
  98.             protected abstract void OnSceneGUI();
  99.  
  100.             public void GUIDrawEditButton(Rect rect)
  101.             {
  102.                 _lastGUIUpdate = Time.time;
  103.                 GUI.color = IsEditing ? Color.red : Color.green;
  104.                 if (!IsEditing && GUI.Button(rect, new GUIContent("Edit", _property.contentHash.ToString())))
  105.                 {
  106.                     foreach (var ctx in _subscribedEditors)
  107.                     {
  108.                         ctx.IsEditing = ctx == this;
  109.                     }
  110.                     SceneView.RepaintAll();
  111.                 }
  112.                 else if (IsEditing && GUI.Button(rect, new GUIContent("Stop Editing", _property.contentHash.ToString())))
  113.                 {
  114.                     IsEditing = false;
  115.                     OnStopped();
  116.                     SceneView.RepaintAll();
  117.                 }
  118.                 GUI.color = Color.white;
  119.             }
  120.         }
  121.     }
  122. }
  123. #endif
Advertisement
Comments
  • zORg_alex
    235 days
    Comment was deleted
  • zORg_alex
    235 days (edited)
    Comment was deleted
  • zORg_alex
    88 days (edited)
    # C# 4.12 KB | 0 0
    1. Example with this PropertyDrawer context class
    2.  
    3. using Scripts.Extensions;
    4. using Scripts.Extensions.Serialized;
    5. using System;
    6. #if UNITY_EDITOR
    7. using UnityEditor;
    8. using UnityEditorInternal;
    9. #endif
    10. using UnityEngine;
    11.  
    12. [SelectionBase]
    13. public class Interactable : MonoBehaviour
    14. {
    15.     [field:SerializeField]
    16.     public InteractionPoint Interaction { get; private set; }
    17.  
    18.     private void Start() => Initialize();
    19.     private void OnEnable()
    20.     {
    21.         this.OnAssemblyReload(Initialize);
    22.         TransformUpdated();
    23.     }
    24.  
    25.     private void TransformUpdated()
    26.     {
    27.         Interaction.TransformUpdated(transform);
    28.     }
    29.  
    30.     private void Initialize()
    31.     {
    32.        
    33.     }
    34.  
    35.     [Serializable]
    36.     public class InteractionPoint
    37.     {
    38.         private Matrix4x4 _localToWorld;
    39.         private Matrix4x4 _worldToLocal;
    40.         [SerializeField]
    41.         private Vector3 _position;
    42.         public Vector3 Position
    43.         {
    44.             get => _localToWorld.MultiplyPoint3x4(_position);
    45.             set => _position = _worldToLocal.MultiplyPoint3x4(value);
    46.         }
    47.         [SerializeField]
    48.         private Quaternion _rotation = Quaternion.identity;
    49.         public Quaternion Rotation
    50.         {
    51.             get => _localToWorld.rotation * _rotation;
    52.             set => _rotation = _worldToLocal.rotation * value;
    53.         }
    54.  
    55.         internal void TransformUpdated(Transform transform)
    56.         {
    57.             _localToWorld = transform.localToWorldMatrix;
    58.             _worldToLocal = transform.worldToLocalMatrix;
    59.         }
    60.  
    61. #if UNITY_EDITOR
    62.         [CustomPropertyDrawer(typeof(InteractionPoint))]
    63.         public class InteractionPointInspector : PropertyDrawer
    64.         {
    65.             private Context _ctx;
    66.  
    67.             public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    68.             {
    69.                 var obj = property.serializedObject.targetObject as MonoBehaviour;
    70.                 var val = property.GetValue<InteractionPoint>();
    71.                 if (obj)
    72.                     val?.TransformUpdated(obj.transform);
    73.  
    74.                 position.height = 18;
    75.                 GUI.Label(position, label);
    76.                 var button = new Rect(
    77.                     position.x + EditorGUIUtility.labelWidth, position.y,
    78.                     position.width - EditorGUIUtility.labelWidth, position.height);
    79.                 if (!Context.TrySubscribing(property, out var ctx)) return;
    80.                 ctx.GUIDrawEditButton(button);
    81.  
    82.                 EditorGUI.indentLevel++;
    83.                 position.y += 20;
    84.                 EditorGUI.PropertyField(position, property.FindPropertyRelative(nameof(InteractionPoint._position)));
    85.                 position.y += 20;
    86.                 EditorGUI.PropertyField(position, property.FindPropertyRelative(nameof(InteractionPoint._rotation)));
    87.                 EditorGUI.indentLevel--;
    88.             }
    89.             public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    90.             {
    91.                 return 18 * 3 + 2 * 2;
    92.             }
    93.             private class Context : SceneViewDrawerExtensions.Context<InteractionPoint, Context>
    94.             {
    95.                 private Tool _lastTool;
    96.                 private InteractionPoint _point => _field;
    97.                 protected override void OnSceneGUI()
    98.                 {
    99.                     if (!InternalEditorUtility.GetIsInspectorExpanded(_object))
    100.                         return;
    101.                     if (IsEditing && Tools.current != Tool.None)
    102.                     {
    103.                         _lastTool = Tools.current;
    104.                         Tools.current = Tool.None;
    105.                     }
    106.  
    107.                     DrawEmpty(_point.Position, _point.Rotation);
    108.                     if (IsEditing && _lastTool == Tool.Move)
    109.                     {
    110.                         var newPos = Handles.PositionHandle(_point.Position, _point.Rotation);
    111.                         if (newPos != _point.Position)
    112.                         {
    113.                             Undo.RecordObject(_object, "HandPose MoveTool");
    114.                             _point.Position = newPos;
    115.                         }
    116.                     }
    117.                     else if (IsEditing && _lastTool == Tool.Rotate)
    118.                     {
    119.                         var newRot = Handles.RotationHandle(_point.Rotation, _point.Position);
    120.                         if (newRot != _point.Rotation)
    121.                         {
    122.                             Undo.RecordObject(_object, "HandPose MoveTool");
    123.                             _point.Rotation = newRot;
    124.                         }
    125.                     }
    126.                 }
    127.  
    128.                 protected override void OnStopped()
    129.                 {
    130.                     Tools.current = _lastTool;
    131.                 }
    132.                 private void DrawEmpty(Vector3 pos, Quaternion rot)
    133.                 {
    134.                     var size = HandleUtility.GetHandleSize(pos);
    135.                     Handles.color = Color.red;
    136.                     Handles.DrawAAPolyLine(pos, pos + rot * Vector3.right * size);
    137.                     Handles.color = Color.green;
    138.                     Handles.DrawAAPolyLine(pos, pos + rot * Vector3.up * size);
    139.                     Handles.color = Color.blue;
    140.                     Handles.DrawAAPolyLine(pos, pos + rot * Vector3.forward * size);
    141.                 }
    142.             }
    143.         }
    144. #endif
    145.     }
    146. }
    147.  
Add Comment
Please, Sign In to add comment
Advertisement