diff --git a/Editor/AbstractPropertyDrawer.cs b/Editor/AbstractPropertyDrawer.cs index c73e9a4..1fc447b 100644 --- a/Editor/AbstractPropertyDrawer.cs +++ b/Editor/AbstractPropertyDrawer.cs @@ -16,7 +16,16 @@ namespace Module.Inspector.Editor bool prevEnabled = GUI.enabled; GUI.enabled = prevEnabled && accessType == EAccessType.Enabled; - + + if (Event.current.type == EventType.Repaint) + { + for (var i = 0; i < result.handleDrawers.Count; i++) + { + EditorPropertyUtility.ResultValue value = result.handleDrawers[i]; + HandleDrawerEditor.Add(value.attribute, property, value.drawer); + } + } + label.tooltip = result.tooltip; for (var i = 0; i < result.predrawerModifiers.Count; i++) diff --git a/Editor/HandleDrawerEditor.cs b/Editor/HandleDrawerEditor.cs new file mode 100644 index 0000000..7dc62eb --- /dev/null +++ b/Editor/HandleDrawerEditor.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace Module.Inspector.Editor +{ + [InitializeOnLoad] + internal static class HandleDrawerEditor + { + private static readonly List ELEMENTS = new List(); + + static HandleDrawerEditor() + { + SceneView.beforeSceneGui -= SceneGUI; + SceneView.beforeSceneGui += SceneGUI; + + Selection.selectionChanged -= OnSelectionChanged; + Selection.selectionChanged += OnSelectionChanged; + } + + private static void SceneGUI(SceneView view) + { + for (int i = ELEMENTS.Count - 1; i >= 0; i--) + { + Element e = ELEMENTS[i]; + bool valid = e.target != null; + + if (e.target != null) + { + var serializedObject = new SerializedObject(e.target); + SerializedProperty serializedProperty = serializedObject.FindProperty(e.propertyPath); + valid = serializedProperty != null && e.drawer.IsValidFor(serializedProperty); + + if (valid) + { + EditorGUI.BeginChangeCheck(); + e.drawer.Draw(e.attribute, serializedProperty); + + if (EditorGUI.EndChangeCheck()) + serializedObject.ApplyModifiedProperties(); + } + + serializedObject.Dispose(); + } + + if (!valid) + ELEMENTS.RemoveAt(i); + } + } + + private static void OnSelectionChanged() + { + ELEMENTS.Clear(); + } + + public static void Add(HandleDrawerPropertyAttribute attribute, SerializedProperty property, HandlePropertyDrawer drawer) + { + ELEMENTS.Add(new Element(attribute, property, drawer)); + } + + public static void Clear() + { + ELEMENTS.Clear(); + } + + private sealed class Element + { + public readonly HandleDrawerPropertyAttribute attribute; + public readonly HandlePropertyDrawer drawer; + public readonly Object target; + public readonly string propertyPath; + + public Element(HandleDrawerPropertyAttribute attribute, SerializedProperty property, HandlePropertyDrawer drawer) + { + this.attribute = attribute; + this.drawer = drawer; + + target = property.serializedObject.targetObject; + propertyPath = property.propertyPath; + } + } + } +} \ No newline at end of file diff --git a/Editor/HandleDrawerEditor.cs.meta b/Editor/HandleDrawerEditor.cs.meta new file mode 100644 index 0000000..fbe04b5 --- /dev/null +++ b/Editor/HandleDrawerEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3357a3447d20469487fd17f88d47ce6d +timeCreated: 1669410085 \ No newline at end of file diff --git a/Editor/HandlePropertyDrawer.cs b/Editor/HandlePropertyDrawer.cs new file mode 100644 index 0000000..0859b03 --- /dev/null +++ b/Editor/HandlePropertyDrawer.cs @@ -0,0 +1,10 @@ +using UnityEditor; + +namespace Module.Inspector.Editor +{ + public abstract class HandlePropertyDrawer : AbstractPropertyDrawer + { + public abstract void Draw(HandleDrawerPropertyAttribute attribute, SerializedProperty serializedProperty); + public abstract bool IsValidFor(SerializedProperty serializedProperty); + } +} \ No newline at end of file diff --git a/Editor/HandlePropertyDrawer.cs.meta b/Editor/HandlePropertyDrawer.cs.meta new file mode 100644 index 0000000..8cad009 --- /dev/null +++ b/Editor/HandlePropertyDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 315f22f458d84fdcb3049f579622c15a +timeCreated: 1669408966 \ No newline at end of file diff --git a/Editor/Handles.meta b/Editor/Handles.meta new file mode 100644 index 0000000..abc637b --- /dev/null +++ b/Editor/Handles.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7347da106b234bc2b88466d8567e92d4 +timeCreated: 1669408266 \ No newline at end of file diff --git a/Editor/Handles/BoxHandleAttributeDrawer.cs b/Editor/Handles/BoxHandleAttributeDrawer.cs new file mode 100644 index 0000000..8d22311 --- /dev/null +++ b/Editor/Handles/BoxHandleAttributeDrawer.cs @@ -0,0 +1,103 @@ +using Module.Inspector.Editor.Utilities; +using UnityEditor; +using UnityEngine; + +namespace Module.Inspector.Editor +{ + [CustomPropertyDrawer(typeof(BoxHandleAttribute))] + internal sealed class BoxHandleAttributeDrawer : HandlePropertyDrawer + { + public override void Draw(HandleDrawerPropertyAttribute attribute, SerializedProperty serializedProperty) + { + var att = (BoxHandleAttribute)attribute; + bool hasPositionField = EditorHandleUtility.TryGetWorldPosition(serializedProperty, att.fieldPosition, att.space, out Vector3 worldPosition); + bool hasRotationField = EditorHandleUtility.TryGetWorldRotation(serializedProperty, att.fieldRotation, att.space, out Quaternion worldRotation); + Vector3 size = GetValue(serializedProperty, out EAxis axii); + Color color = Handles.color; + + if (hasPositionField) + worldPosition = EditorHandleUtility.PositionHandle(worldPosition, worldRotation); + if (hasRotationField) + worldRotation = EditorHandleUtility.RotationHandle(worldPosition, worldRotation); + + size = EditorHandleUtility.BoxHandle(worldPosition, worldRotation, size, axii); + + if (hasPositionField) + EditorHandleUtility.SetWorldPosition(serializedProperty, att.fieldPosition, worldPosition, att.space); + if (hasRotationField) + EditorHandleUtility.SetWorldRotation(serializedProperty, att.fieldRotation, worldRotation, att.space); + + SetValue(serializedProperty, size); + Handles.color = color; + } + + private Vector3 GetValue(SerializedProperty serializedProperty, out EAxis axii) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + axii = EAxis.X; + return new Vector3(serializedProperty.intValue, serializedProperty.intValue, serializedProperty.intValue); + case SerializedPropertyType.Float: + axii = EAxis.X; + return new Vector3(serializedProperty.floatValue, serializedProperty.floatValue, serializedProperty.floatValue); + case SerializedPropertyType.Vector2: + axii = EAxis.X | EAxis.Y; + return new Vector3(serializedProperty.vector2Value.x, serializedProperty.vector2Value.y, 0f); + case SerializedPropertyType.Vector3: + axii = EAxis.All; + return serializedProperty.vector3Value; + case SerializedPropertyType.Vector2Int: + axii = EAxis.X | EAxis.Y; + return new Vector3(serializedProperty.vector2IntValue.x, serializedProperty.vector2IntValue.y, 0f); + case SerializedPropertyType.Vector3Int: + axii = EAxis.All; + return serializedProperty.vector3IntValue; + default: + axii = EAxis.X; + return Vector3.one; + } + } + + private void SetValue(SerializedProperty serializedProperty, Vector3 value) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + serializedProperty.intValue = Mathf.RoundToInt(value.x); + break; + case SerializedPropertyType.Float: + serializedProperty.floatValue = value.x; + break; + case SerializedPropertyType.Vector2: + serializedProperty.vector2Value = new Vector2(value.x, value.y); + break; + case SerializedPropertyType.Vector3: + serializedProperty.vector3Value = value; + break; + case SerializedPropertyType.Vector2Int: + serializedProperty.vector2IntValue = new Vector2Int(Mathf.RoundToInt(value.x), Mathf.RoundToInt(value.y)); + break; + case SerializedPropertyType.Vector3Int: + serializedProperty.vector3IntValue = new Vector3Int(Mathf.RoundToInt(value.x), Mathf.RoundToInt(value.y), Mathf.RoundToInt(value.z)); + break; + } + } + + public override bool IsValidFor(SerializedProperty serializedProperty) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + case SerializedPropertyType.Float: + case SerializedPropertyType.Vector2: + case SerializedPropertyType.Vector3: + case SerializedPropertyType.Vector2Int: + case SerializedPropertyType.Vector3Int: + return true; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/Editor/Handles/BoxHandleAttributeDrawer.cs.meta b/Editor/Handles/BoxHandleAttributeDrawer.cs.meta new file mode 100644 index 0000000..d844940 --- /dev/null +++ b/Editor/Handles/BoxHandleAttributeDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3dfa4467da7444549585b2992516427e +timeCreated: 1669475655 \ No newline at end of file diff --git a/Editor/Handles/CircleHandleAttributeDrawer.cs b/Editor/Handles/CircleHandleAttributeDrawer.cs new file mode 100644 index 0000000..68200a1 --- /dev/null +++ b/Editor/Handles/CircleHandleAttributeDrawer.cs @@ -0,0 +1,72 @@ +using Module.Inspector.Editor.Utilities; +using UnityEditor; +using UnityEngine; + +namespace Module.Inspector.Editor +{ + [CustomPropertyDrawer(typeof(CircleHandleAttribute))] + internal sealed class CircleHandleAttributeDrawer : HandlePropertyDrawer + { + public override void Draw(HandleDrawerPropertyAttribute attribute, SerializedProperty serializedProperty) + { + var att = (CircleHandleAttribute)attribute; + bool hasPositionField = EditorHandleUtility.TryGetWorldPosition(serializedProperty, att.fieldPosition, att.space, out Vector3 worldPosition); + bool hasRotationField = EditorHandleUtility.TryGetWorldRotation(serializedProperty, att.fieldRotation, att.space, out Quaternion worldRotation); + float size = GetValue(serializedProperty); + Color color = Handles.color; + + if (hasPositionField) + worldPosition = EditorHandleUtility.PositionHandle(worldPosition, worldRotation); + if (hasRotationField) + worldRotation = EditorHandleUtility.RotationHandle(worldPosition, worldRotation); + + size = EditorHandleUtility.CircleHandle(worldPosition, worldRotation, size); + + if (hasPositionField) + EditorHandleUtility.SetWorldPosition(serializedProperty, att.fieldPosition, worldPosition, att.space); + if (hasRotationField) + EditorHandleUtility.SetWorldRotation(serializedProperty, att.fieldRotation, worldRotation, att.space); + + SetValue(serializedProperty, size); + Handles.color = color; + } + + private float GetValue(SerializedProperty serializedProperty) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + return serializedProperty.intValue; + case SerializedPropertyType.Float: + return serializedProperty.floatValue; + default: + return 1f; + } + } + + private void SetValue(SerializedProperty serializedProperty, float value) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + serializedProperty.intValue = Mathf.RoundToInt(value); + break; + case SerializedPropertyType.Float: + serializedProperty.floatValue = value; + break; + } + } + + public override bool IsValidFor(SerializedProperty serializedProperty) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + case SerializedPropertyType.Float: + return true; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/Editor/Handles/CircleHandleAttributeDrawer.cs.meta b/Editor/Handles/CircleHandleAttributeDrawer.cs.meta new file mode 100644 index 0000000..f05c01b --- /dev/null +++ b/Editor/Handles/CircleHandleAttributeDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1ec82d143086477aa01a1ce9634b2689 +timeCreated: 1669475467 \ No newline at end of file diff --git a/Editor/Handles/LabelHandleAttributeDrawer.cs b/Editor/Handles/LabelHandleAttributeDrawer.cs new file mode 100644 index 0000000..6392bf1 --- /dev/null +++ b/Editor/Handles/LabelHandleAttributeDrawer.cs @@ -0,0 +1,46 @@ +using System.Text; +using Module.Inspector.Editor.Utilities; +using UnityEditor; +using UnityEngine; + +namespace Module.Inspector.Editor +{ + [CustomPropertyDrawer(typeof(LabelHandleAttribute))] + internal sealed class LabelHandleAttributeDrawer : HandlePropertyDrawer + { + private readonly StringBuilder builder = new StringBuilder(); + private GUIStyle style; + + public override void Draw(HandleDrawerPropertyAttribute attribute, SerializedProperty serializedProperty) + { + var att = (LabelHandleAttribute)attribute; + Vector3 wp = EditorHandleUtility.GetWorldPosition(serializedProperty, att.fieldPosition, att.space); + + if (style == null) + { + style = new GUIStyle(GUI.skin.label); + style.alignment = TextAnchor.MiddleCenter; + } + + builder.Clear(); + + if ((att.type & ELabelType.Field) != 0) + builder.Append(serializedProperty.displayName); + + if ((att.type & ELabelType.Value) != 0) + { + if ((att.type & ELabelType.Field) != 0) + builder.Append('\n'); + + builder.Append(serializedProperty.GetValueAsString()); + } + + Handles.Label(wp, builder.ToString(), style); + } + + public override bool IsValidFor(SerializedProperty serializedProperty) + { + return true; + } + } +} \ No newline at end of file diff --git a/Editor/Handles/LabelHandleAttributeDrawer.cs.meta b/Editor/Handles/LabelHandleAttributeDrawer.cs.meta new file mode 100644 index 0000000..041f2a4 --- /dev/null +++ b/Editor/Handles/LabelHandleAttributeDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9a9cc06839c34083a5e8793dab6ac651 +timeCreated: 1669475780 \ No newline at end of file diff --git a/Editor/Handles/PositionHandleAttributeDrawer.cs b/Editor/Handles/PositionHandleAttributeDrawer.cs new file mode 100644 index 0000000..8f78f20 --- /dev/null +++ b/Editor/Handles/PositionHandleAttributeDrawer.cs @@ -0,0 +1,40 @@ +using Module.Inspector.Editor.Utilities; +using UnityEditor; +using UnityEngine; + +namespace Module.Inspector.Editor +{ + [CustomPropertyDrawer(typeof(PositionHandleAttribute))] + internal sealed class PositionHandleAttributeDrawer : HandlePropertyDrawer + { + public override void Draw(HandleDrawerPropertyAttribute attribute, SerializedProperty serializedProperty) + { + var att = (PositionHandleAttribute)attribute; + Vector3 worldPosition = EditorHandleUtility.GetWorldPosition(serializedProperty, att.space); + Quaternion worldRotation = EditorHandleUtility.GetWorldRotation(serializedProperty, att.space); + Color color = Handles.color; + + worldPosition = EditorHandleUtility.PositionHandle(worldPosition, worldRotation, att.axiis); + EditorHandleUtility.SetWorldPosition(serializedProperty, worldPosition, att.space); + Handles.color = color; + } + + public override bool IsValidFor(SerializedProperty serializedProperty) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + case SerializedPropertyType.Float: + case SerializedPropertyType.Vector2: + case SerializedPropertyType.Vector3: + case SerializedPropertyType.Vector2Int: + case SerializedPropertyType.Vector3Int: + return true; + case SerializedPropertyType.ObjectReference: + return serializedProperty.objectReferenceValue != null && serializedProperty.objectReferenceValue is Transform; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/Editor/Handles/PositionHandleAttributeDrawer.cs.meta b/Editor/Handles/PositionHandleAttributeDrawer.cs.meta new file mode 100644 index 0000000..aea242b --- /dev/null +++ b/Editor/Handles/PositionHandleAttributeDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 517a50351ebe49549d55dfe6c037941c +timeCreated: 1669408276 \ No newline at end of file diff --git a/Editor/Handles/RectangleHandleAttributeDrawer.cs b/Editor/Handles/RectangleHandleAttributeDrawer.cs new file mode 100644 index 0000000..804f215 --- /dev/null +++ b/Editor/Handles/RectangleHandleAttributeDrawer.cs @@ -0,0 +1,103 @@ +using Module.Inspector.Editor.Utilities; +using UnityEditor; +using UnityEngine; + +namespace Module.Inspector.Editor +{ + [CustomPropertyDrawer(typeof(RectangleHandleAttribute))] + internal sealed class RectangleHandleAttributeDrawer : HandlePropertyDrawer + { + public override void Draw(HandleDrawerPropertyAttribute attribute, SerializedProperty serializedProperty) + { + var att = (RectangleHandleAttribute)attribute; + bool hasPositionField = EditorHandleUtility.TryGetWorldPosition(serializedProperty, att.fieldPosition, att.space, out Vector3 worldPosition); + bool hasRotationField = EditorHandleUtility.TryGetWorldRotation(serializedProperty, att.fieldRotation, att.space, out Quaternion worldRotation); + Vector2 size = GetValue(serializedProperty, out EAxis axii); + Color color = Handles.color; + + if (hasPositionField) + worldPosition = EditorHandleUtility.PositionHandle(worldPosition, worldRotation); + if (hasRotationField) + worldRotation = EditorHandleUtility.RotationHandle(worldPosition, worldRotation); + + size = EditorHandleUtility.RectHandle(worldPosition, worldRotation, size, axii); + + if (hasPositionField) + EditorHandleUtility.SetWorldPosition(serializedProperty, att.fieldPosition, worldPosition, att.space); + if (hasRotationField) + EditorHandleUtility.SetWorldRotation(serializedProperty, att.fieldRotation, worldRotation, att.space); + + SetValue(serializedProperty, size); + Handles.color = color; + } + + private Vector2 GetValue(SerializedProperty serializedProperty, out EAxis axii) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + axii = EAxis.X; + return new Vector2(serializedProperty.intValue, serializedProperty.intValue); + case SerializedPropertyType.Float: + axii = EAxis.X; + return new Vector2(serializedProperty.floatValue, serializedProperty.floatValue); + case SerializedPropertyType.Vector2: + axii = EAxis.All; + return serializedProperty.vector2Value; + case SerializedPropertyType.Vector3: + axii = EAxis.All; + return serializedProperty.vector3Value; + case SerializedPropertyType.Vector2Int: + axii = EAxis.All; + return serializedProperty.vector2IntValue; + case SerializedPropertyType.Vector3Int: + axii = EAxis.All; + return new Vector2(serializedProperty.vector3IntValue.x, serializedProperty.vector3IntValue.y); + default: + axii = EAxis.None; + return Vector2.one; + } + } + + private void SetValue(SerializedProperty serializedProperty, Vector2 value) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + serializedProperty.intValue = Mathf.RoundToInt(value.x); + break; + case SerializedPropertyType.Float: + serializedProperty.floatValue = value.x; + break; + case SerializedPropertyType.Vector2: + serializedProperty.vector2Value = value; + break; + case SerializedPropertyType.Vector3: + serializedProperty.vector3Value = value; + break; + case SerializedPropertyType.Vector2Int: + serializedProperty.vector2IntValue = new Vector2Int(Mathf.RoundToInt(value.x), Mathf.RoundToInt(value.y)); + break; + case SerializedPropertyType.Vector3Int: + serializedProperty.vector3IntValue = new Vector3Int(Mathf.RoundToInt(value.x), Mathf.RoundToInt(value.y), 0); + break; + } + } + + public override bool IsValidFor(SerializedProperty serializedProperty) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + case SerializedPropertyType.Float: + case SerializedPropertyType.Vector2: + case SerializedPropertyType.Vector3: + case SerializedPropertyType.Vector2Int: + case SerializedPropertyType.Vector3Int: + return true; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/Editor/Handles/RectangleHandleAttributeDrawer.cs.meta b/Editor/Handles/RectangleHandleAttributeDrawer.cs.meta new file mode 100644 index 0000000..990fd0b --- /dev/null +++ b/Editor/Handles/RectangleHandleAttributeDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: add3ba2b5b1c46088aaf8604ce8929f8 +timeCreated: 1669475681 \ No newline at end of file diff --git a/Editor/Handles/RotationHandleAttributeDrawer.cs b/Editor/Handles/RotationHandleAttributeDrawer.cs new file mode 100644 index 0000000..cf52a86 --- /dev/null +++ b/Editor/Handles/RotationHandleAttributeDrawer.cs @@ -0,0 +1,40 @@ +using Module.Inspector.Editor.Utilities; +using UnityEditor; +using UnityEngine; + +namespace Module.Inspector.Editor +{ + [CustomPropertyDrawer(typeof(RotationHandleAttribute))] + internal sealed class RotationHandleAttributeDrawer : HandlePropertyDrawer + { + public override void Draw(HandleDrawerPropertyAttribute attribute, SerializedProperty serializedProperty) + { + var att = (RotationHandleAttribute)attribute; + bool hasPositionField = EditorHandleUtility.TryGetWorldPosition(serializedProperty, att.fieldPosition, att.space, out Vector3 worldPosition); + Quaternion worldRotation = EditorHandleUtility.GetWorldRotation(serializedProperty, att.space); + Color color = Handles.color; + + if (hasPositionField) + worldPosition = EditorHandleUtility.PositionHandle(worldPosition, worldRotation); + + worldRotation = EditorHandleUtility.RotationHandle(worldPosition, worldRotation); + + if (hasPositionField) + EditorHandleUtility.SetWorldPosition(serializedProperty, att.fieldPosition, worldPosition, att.space); + + EditorHandleUtility.SetWorldRotation(serializedProperty, worldRotation, att.space); + Handles.color = color; + } + + public override bool IsValidFor(SerializedProperty serializedProperty) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Quaternion: + return true; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/Editor/Handles/RotationHandleAttributeDrawer.cs.meta b/Editor/Handles/RotationHandleAttributeDrawer.cs.meta new file mode 100644 index 0000000..34811f7 --- /dev/null +++ b/Editor/Handles/RotationHandleAttributeDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9193d6531ba843749d9fd78bc6b166d7 +timeCreated: 1669475582 \ No newline at end of file diff --git a/Editor/Handles/SphereHandleAttributeDrawer.cs b/Editor/Handles/SphereHandleAttributeDrawer.cs new file mode 100644 index 0000000..11cf6eb --- /dev/null +++ b/Editor/Handles/SphereHandleAttributeDrawer.cs @@ -0,0 +1,72 @@ +using Module.Inspector.Editor.Utilities; +using UnityEditor; +using UnityEngine; + +namespace Module.Inspector.Editor +{ + [CustomPropertyDrawer(typeof(SphereHandleAttribute))] + internal sealed class SphereHandleAttributeDrawer : HandlePropertyDrawer + { + public override void Draw(HandleDrawerPropertyAttribute attribute, SerializedProperty serializedProperty) + { + var att = (SphereHandleAttribute)attribute; + bool hasPositionField = EditorHandleUtility.TryGetWorldPosition(serializedProperty, att.fieldPosition, att.space, out Vector3 worldPosition); + bool hasRotationField = EditorHandleUtility.TryGetWorldRotation(serializedProperty, att.fieldRotation, att.space, out Quaternion worldRotation); + float size = GetValue(serializedProperty); + Color color = Handles.color; + + if (hasPositionField) + worldPosition = EditorHandleUtility.PositionHandle(worldPosition, worldRotation); + if (hasRotationField) + worldRotation = EditorHandleUtility.RotationHandle(worldPosition, worldRotation); + + size = EditorHandleUtility.SphereHandle(worldPosition, worldRotation, size); + + if (hasPositionField) + EditorHandleUtility.SetWorldPosition(serializedProperty, att.fieldPosition, worldPosition, att.space); + if (hasRotationField) + EditorHandleUtility.SetWorldRotation(serializedProperty, att.fieldRotation, worldRotation, att.space); + + SetValue(serializedProperty, size); + Handles.color = color; + } + + private float GetValue(SerializedProperty serializedProperty) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + return serializedProperty.intValue; + case SerializedPropertyType.Float: + return serializedProperty.floatValue; + default: + return 1f; + } + } + + private void SetValue(SerializedProperty serializedProperty, float value) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + serializedProperty.intValue = Mathf.RoundToInt(value); + break; + case SerializedPropertyType.Float: + serializedProperty.floatValue = value; + break; + } + } + + public override bool IsValidFor(SerializedProperty serializedProperty) + { + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + case SerializedPropertyType.Float: + return true; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/Editor/Handles/SphereHandleAttributeDrawer.cs.meta b/Editor/Handles/SphereHandleAttributeDrawer.cs.meta new file mode 100644 index 0000000..4be0173 --- /dev/null +++ b/Editor/Handles/SphereHandleAttributeDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 199eb743ed1846d498b6bbba499cf9f6 +timeCreated: 1669475521 \ No newline at end of file diff --git a/Editor/ObjectEditor.cs b/Editor/ObjectEditor.cs index ef9932a..7bc80e4 100644 --- a/Editor/ObjectEditor.cs +++ b/Editor/ObjectEditor.cs @@ -10,11 +10,14 @@ namespace Module.Inspector.Editor { public override void OnInspectorGUI() { + if (Event.current.type == EventType.Repaint) + HandleDrawerEditor.Clear(); + DrawDefaultInspector(); DrawHiddenInspector(); DrawMethodInspector(); } - + private void DrawHiddenInspector() { if (!IsValidTarget()) diff --git a/Editor/Utilities/EditorHandleUtility.cs b/Editor/Utilities/EditorHandleUtility.cs new file mode 100644 index 0000000..3ad2f9e --- /dev/null +++ b/Editor/Utilities/EditorHandleUtility.cs @@ -0,0 +1,470 @@ +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Module.Inspector.Editor.Utilities +{ + public static class EditorHandleUtility + { + private static readonly Color DEFAULT_AXIS_COLOR = new Color(0.7f, 0.7f, 0.7f, 0.93f); + private static readonly Color X_AXIS_COLOR = new Color(0.85882354f, 0.24313726f, 0.11372549f, 0.93f); + private static readonly Color Y_AXIS_COLOR = new Color(0.6039216f, 0.9529412f, 0.28235295f, 0.93f); + private static readonly Color Z_AXIS_COLOR = new Color(0.22745098f, 0.47843137f, 0.972549f, 0.93f); + + private static readonly Color EDGE_COLOR = new Color(0.6039216f, 0.9529412f, 0.28235295f, 0.93f); + private static readonly Color EDGE_COLOR2 = new Color(0.6039216f, 0.9529412f, 0.28235295f, 0.4f); + + private static readonly Quaternion CIRCLE_CAP_ROTATION = Quaternion.Euler(90f, 0f, 0f); + private static readonly Quaternion CIRCLE_CAP_ROTATION2 = Quaternion.Euler(0f, 90f, 0f); + private static readonly Quaternion RECTANGLE_CAP_ROTATION = Quaternion.Euler(90f, 0f, 0f); + + public static Vector2 RectHandle(Vector3 worldPosition, Quaternion worldRotation, Vector2 rectSize, EAxis axii) + { + float size = HandleUtility.GetHandleSize(worldPosition); + float dotSize = size * 0.125f; + + Handles.matrix = Matrix4x4.TRS(worldPosition, worldRotation * RECTANGLE_CAP_ROTATION, Vector3.one); + Color color = Handles.color; + + Handles.color = EDGE_COLOR; + Handles.DrawWireCube(Vector3.zero, rectSize); + + if ((axii & EAxis.X) != 0) + { + var point = new Vector3(rectSize.x * 0.5f, 0f, 0f); + Handles.color = DEFAULT_AXIS_COLOR; + point = Handles.Slider(point, Vector3.right, dotSize, Handles.CubeHandleCap, 0.01f); + rectSize.x = Mathf.Max(point.x, 0f) * 2f; + } + + if ((axii & EAxis.Y) != 0) + { + var point = new Vector3(0f, rectSize.y * 0.5f, 0f); + Handles.color = DEFAULT_AXIS_COLOR; + point = Handles.Slider(point, Vector3.up, dotSize, Handles.CubeHandleCap, 0.01f); + rectSize.y = Mathf.Max(point.y, 0f) * 2f; + } + + Handles.color = color; + Handles.matrix = Matrix4x4.identity; + return rectSize; + } + + public static float CircleHandle(Vector3 worldPosition, Quaternion worldRotation, float circleSize) + { + float size = HandleUtility.GetHandleSize(worldPosition); + float dotSize = size * 0.125f; + + Handles.matrix = Matrix4x4.TRS(worldPosition, worldRotation, Vector3.one); + Color color = Handles.color; + + Handles.color = EDGE_COLOR; + Handles.CircleHandleCap(-1, Vector3.zero, CIRCLE_CAP_ROTATION, circleSize, EventType.Repaint); + + var point = new Vector3(circleSize, 0f, 0f); + Handles.color = DEFAULT_AXIS_COLOR; + point = Handles.Slider(point, Vector3.right, dotSize, Handles.CubeHandleCap, 0.01f); + circleSize = Mathf.Max(point.x, 0f); + + Handles.color = color; + Handles.matrix = Matrix4x4.identity; + return circleSize; + } + + public static float SphereHandle(Vector3 worldPosition, Quaternion worldRotation, float sphereSize) + { + float size = HandleUtility.GetHandleSize(worldPosition); + float dotSize = size * 0.125f; + + Handles.matrix = Matrix4x4.TRS(worldPosition, worldRotation, Vector3.one); + Color color = Handles.color; + + Handles.color = EDGE_COLOR; + Handles.CircleHandleCap(-1, Vector3.zero, CIRCLE_CAP_ROTATION, sphereSize, EventType.Repaint); + + Handles.color = EDGE_COLOR2; + Handles.CircleHandleCap(-1, Vector3.zero, Quaternion.identity, sphereSize, EventType.Repaint); + Handles.CircleHandleCap(-1, Vector3.zero, CIRCLE_CAP_ROTATION2, sphereSize, EventType.Repaint); + + var point = new Vector3(sphereSize, 0f, 0f); + Handles.color = DEFAULT_AXIS_COLOR; + point = Handles.Slider(point, Vector3.right, dotSize, Handles.CubeHandleCap, 0.01f); + sphereSize = Mathf.Max(point.x, 0f); + + Handles.color = color; + Handles.matrix = Matrix4x4.identity; + return sphereSize; + } + + public static Vector3 BoxHandle(Vector3 worldPosition, Quaternion worldRotation, Vector3 boxSize, EAxis axii = EAxis.All) + { + float size = HandleUtility.GetHandleSize(worldPosition); + float dotSize = size * 0.125f; + + Handles.matrix = Matrix4x4.TRS(worldPosition, worldRotation, Vector3.one); + Color color = Handles.color; + + Handles.color = EDGE_COLOR; + Handles.DrawWireCube(Vector3.zero, boxSize); + + if ((axii & EAxis.X) != 0) + { + var point = new Vector3(boxSize.x * 0.5f, 0f, 0f); + Handles.color = DEFAULT_AXIS_COLOR; + point = Handles.Slider(point, Vector3.right, dotSize, Handles.CubeHandleCap, 0.01f); + boxSize.x = Mathf.Max(point.x, 0f) * 2f; + } + + if ((axii & EAxis.Y) != 0) + { + var point = new Vector3(0f, boxSize.y * 0.5f, 0f); + Handles.color = DEFAULT_AXIS_COLOR; + point = Handles.Slider(point, Vector3.up, dotSize, Handles.CubeHandleCap, 0.01f); + boxSize.y = Mathf.Max(point.y, 0f) * 2f; + } + + if ((axii & EAxis.Z) != 0) + { + var point = new Vector3(0f, 0f, boxSize.z * 0.5f); + Handles.color = DEFAULT_AXIS_COLOR; + point = Handles.Slider(point, Vector3.forward, dotSize, Handles.CubeHandleCap, 0.01f); + boxSize.z = Mathf.Max(point.z, 0f) * 2f; + } + + Handles.color = color; + Handles.matrix = Matrix4x4.identity; + return boxSize; + } + + public static Vector3 PositionHandle(Vector3 worldPosition, Quaternion worldRotation, EAxis axii = EAxis.All) + { + float size = HandleUtility.GetHandleSize(worldPosition); + float twoAxisSize = size * 0.1f; + Color color = Handles.color; + + if ((axii & (EAxis.X | EAxis.Y)) == (EAxis.X | EAxis.Y)) + { + Handles.color = Z_AXIS_COLOR; + Vector3 offset = worldRotation * new Vector3(twoAxisSize, twoAxisSize, 0f); + + worldPosition = Handles.Slider2D(worldPosition + offset, + worldRotation * Vector3.forward, + worldRotation * Vector3.right, + worldRotation * Vector3.up, twoAxisSize, + Handles.RectangleHandleCap, 0.01f) - offset; + } + + if ((axii & (EAxis.X | EAxis.Z)) == (EAxis.X | EAxis.Z)) + { + Handles.color = Y_AXIS_COLOR; + Vector3 offset = worldRotation * new Vector3(twoAxisSize, 0f, twoAxisSize); + + worldPosition = Handles.Slider2D(worldPosition + offset, + worldRotation * Vector3.up, + worldRotation * Vector3.right, + worldRotation * Vector3.forward, twoAxisSize, + Handles.RectangleHandleCap, 0.01f) - offset; + } + + if ((axii & (EAxis.Y | EAxis.Z)) == (EAxis.Y | EAxis.Z)) + { + Handles.color = X_AXIS_COLOR; + Vector3 offset = worldRotation * new Vector3(0f, twoAxisSize, twoAxisSize); + + worldPosition = Handles.Slider2D(worldPosition + offset, + worldRotation * Vector3.right, + worldRotation * Vector3.up, + worldRotation * Vector3.forward, twoAxisSize, + Handles.RectangleHandleCap, 0.01f) - offset; + } + + if ((axii & EAxis.X) != 0) + { + Handles.color = X_AXIS_COLOR; + worldPosition = Handles.Slider(worldPosition, worldRotation * Vector3.right, size, Handles.ArrowHandleCap, 0.01f); + } + + if ((axii & EAxis.Y) != 0) + { + Handles.color = Y_AXIS_COLOR; + worldPosition = Handles.Slider(worldPosition, worldRotation * Vector3.up, size, Handles.ArrowHandleCap, 0.01f); + } + + if ((axii & EAxis.Z) != 0) + { + Handles.color = Z_AXIS_COLOR; + worldPosition = Handles.Slider(worldPosition, worldRotation * Vector3.forward, size, Handles.ArrowHandleCap, 0.01f); + } + + Handles.color = color; + return worldPosition; + } + + public static Quaternion RotationHandle(Vector3 worldPosition, Quaternion worldRotation) + { + Color color = Handles.color; + worldRotation = Handles.RotationHandle(worldRotation, worldPosition); + Handles.color = color; + return worldRotation; + } + public static bool TryGetWorldPosition(SerializedProperty serializedProperty, string fieldPosition, Space space, out Vector3 worldPosition) + { + SerializedProperty spPosition = serializedProperty.GetSibling(fieldPosition); + + if (spPosition != null) + { + worldPosition = GetWorldPosition(spPosition, space); + } + else + { + Transform transform = GetTransform(serializedProperty); + worldPosition = transform != null ? transform.position : Vector3.zero; + } + + return spPosition != null; + } + + public static Vector3 GetWorldPosition(SerializedProperty serializedProperty, string fieldPosition, Space space) + { + Vector3 worldPosition = Vector3.zero; + SerializedProperty spPosition = serializedProperty.GetSibling(fieldPosition); + + if (spPosition != null) + { + worldPosition = GetWorldPosition(spPosition, space); + } + else + { + Transform transform = GetTransform(serializedProperty); + + if (transform != null) + worldPosition = transform.position; + } + + return worldPosition; + } + + private static Transform GetTransform(SerializedProperty serializedProperty) + { + Object target = serializedProperty.serializedObject.targetObject; + + if (target is Component component) + return component.transform; + + return null; + } + + public static Vector3 GetWorldPosition(SerializedProperty serializedProperty, Space space) + { + Vector3 worldPosition = Vector3.zero; + var requireObjectTransform = true; + + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + worldPosition = new Vector3(serializedProperty.intValue, serializedProperty.intValue, serializedProperty.intValue); + break; + case SerializedPropertyType.Float: + worldPosition = new Vector3(serializedProperty.floatValue, serializedProperty.floatValue, serializedProperty.floatValue); + break; + case SerializedPropertyType.ObjectReference: + if (serializedProperty.objectReferenceValue != null && serializedProperty.objectReferenceValue is Transform transform) + { + worldPosition = transform.position; + requireObjectTransform = false; + } + break; + case SerializedPropertyType.Vector2: + worldPosition = serializedProperty.vector2Value; + break; + case SerializedPropertyType.Vector3: + worldPosition = serializedProperty.vector3Value; + break; + case SerializedPropertyType.Vector2Int: + worldPosition = new Vector3(serializedProperty.vector2IntValue.x, serializedProperty.vector2IntValue.y, 0.0f); + break; + case SerializedPropertyType.Vector3Int: + worldPosition = new Vector3(serializedProperty.vector3IntValue.x, serializedProperty.vector3IntValue.y, serializedProperty.vector3IntValue.z); + break; + } + + if (requireObjectTransform && space == Space.Self) + { + Transform objectTransform = GetTransform(serializedProperty); + + if (objectTransform != null) + worldPosition = objectTransform.TransformPoint(worldPosition); + } + + return worldPosition; + } + + public static void SetWorldPosition(SerializedProperty serializedProperty, string fieldPosition, Vector3 worldPosition, Space space) + { + SerializedProperty spPosition = serializedProperty.GetSibling(fieldPosition); + + if (spPosition != null) + { + SetWorldPosition(spPosition, worldPosition, space); + } + else + { + Transform transform = GetTransform(serializedProperty); + + if (transform != null) + transform.position = worldPosition; + } + } + + public static void SetWorldPosition(SerializedProperty serializedProperty, Vector3 worldPosition, Space space) + { + bool requireObjectTransform = !(serializedProperty.propertyType == SerializedPropertyType.ObjectReference && serializedProperty.objectReferenceValue != null && serializedProperty.objectReferenceValue is Transform); + + if (requireObjectTransform && space == Space.Self) + { + Transform objectTransform = GetTransform(serializedProperty); + + if (objectTransform != null) + worldPosition = objectTransform.InverseTransformPoint(worldPosition); + } + + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.Integer: + serializedProperty.intValue = Mathf.RoundToInt(worldPosition.x); + break; + case SerializedPropertyType.Float: + serializedProperty.floatValue = worldPosition.x; + break; + case SerializedPropertyType.ObjectReference: + if (serializedProperty.objectReferenceValue != null && serializedProperty.objectReferenceValue is Transform transform) + transform.position = worldPosition; + break; + case SerializedPropertyType.Vector2: + serializedProperty.vector2Value = worldPosition; + break; + case SerializedPropertyType.Vector3: + serializedProperty.vector3Value = worldPosition; + break; + case SerializedPropertyType.Vector2Int: + serializedProperty.vector2IntValue = new Vector2Int(Mathf.RoundToInt(worldPosition.x), Mathf.RoundToInt(worldPosition.y)); + break; + case SerializedPropertyType.Vector3Int: + serializedProperty.vector3IntValue = new Vector3Int(Mathf.RoundToInt(worldPosition.x), Mathf.RoundToInt(worldPosition.y), Mathf.RoundToInt(worldPosition.z)); + break; + } + } + + public static bool TryGetWorldRotation(SerializedProperty serializedProperty, string fieldRotation, Space space, out Quaternion worldRotation) + { + SerializedProperty spRotation = serializedProperty.GetSibling(fieldRotation); + + if (spRotation != null) + { + worldRotation = GetWorldRotation(spRotation, space); + } + else + { + Transform transform = GetTransform(serializedProperty); + worldRotation = transform != null ? transform.rotation : Quaternion.identity; + } + + return spRotation != null; + } + + public static Quaternion GetWorldRotation(SerializedProperty serializedProperty, string fieldRotation, Space space) + { + Quaternion worldRotation = Quaternion.identity; + SerializedProperty spRotation = serializedProperty.GetSibling(fieldRotation); + + if (spRotation != null) + { + worldRotation = GetWorldRotation(spRotation, space); + } + else + { + Transform transform = GetTransform(serializedProperty); + + if (transform != null) + worldRotation = transform.rotation; + } + + return worldRotation; + } + + public static Quaternion GetWorldRotation(SerializedProperty serializedProperty, Space space) + { + Quaternion worldRotation = Quaternion.identity; + var requireObjectTransform = true; + + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.ObjectReference: + if (serializedProperty.objectReferenceValue is Transform transform) + { + worldRotation = transform.rotation; + requireObjectTransform = false; + } + + break; + case SerializedPropertyType.Quaternion: + worldRotation = serializedProperty.quaternionValue; + + if (Mathf.Approximately(worldRotation.x, 0.0f) && Mathf.Approximately(worldRotation.y, 0.0f) && Mathf.Approximately(worldRotation.z, 0.0f) && Mathf.Approximately(worldRotation.w, 0.0f)) + worldRotation = Quaternion.identity; + break; + } + + if (requireObjectTransform && space == Space.Self) + { + Transform objectTransform = GetTransform(serializedProperty); + + if (objectTransform != null) + worldRotation = objectTransform.rotation * worldRotation; + } + + return worldRotation; + } + + public static void SetWorldRotation(SerializedProperty serializedProperty, string fieldRotation, Quaternion worldRotation, Space space) + { + SerializedProperty spRotation = serializedProperty.GetSibling(fieldRotation); + + if (spRotation != null) + { + SetWorldRotation(spRotation, worldRotation, space); + } + else + { + Transform transform = GetTransform(serializedProperty); + + if (transform != null) + transform.rotation = worldRotation; + } + } + + public static void SetWorldRotation(SerializedProperty serializedProperty, Quaternion worldRotation, Space space) + { + bool requireObjectTransform = !(serializedProperty.propertyType == SerializedPropertyType.ObjectReference && serializedProperty.objectReferenceValue != null && serializedProperty.objectReferenceValue is Transform); + + if (requireObjectTransform && space == Space.Self) + { + Transform objectTransform = GetTransform(serializedProperty); + + if (objectTransform != null) + worldRotation = Quaternion.Inverse(objectTransform.rotation) * worldRotation; + } + + switch (serializedProperty.propertyType) + { + case SerializedPropertyType.ObjectReference: + if (serializedProperty.objectReferenceValue is Transform transform) + transform.rotation = worldRotation; + break; + case SerializedPropertyType.Quaternion: + serializedProperty.quaternionValue = worldRotation; + break; + } + } + } +} \ No newline at end of file diff --git a/Editor/Utilities/EditorHandleUtility.cs.meta b/Editor/Utilities/EditorHandleUtility.cs.meta new file mode 100644 index 0000000..2c9aba6 --- /dev/null +++ b/Editor/Utilities/EditorHandleUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 45835ab2c4434b40a10616e608e4ce1b +timeCreated: 1669476070 \ No newline at end of file diff --git a/Editor/Utilities/EditorPropertyUtility.cs b/Editor/Utilities/EditorPropertyUtility.cs index 7d17013..753d8f8 100644 --- a/Editor/Utilities/EditorPropertyUtility.cs +++ b/Editor/Utilities/EditorPropertyUtility.cs @@ -76,6 +76,7 @@ namespace Module.Inspector.Editor.Utilities var valueModifiers = new List>(2); var accessModifiers = new List>(2); var validators = new List>(2); + var handleDrawers = new List>(2); object[] attributes = fieldInfo.GetCustomAttributes(false); string tooltip = null; var isObsolete = false; @@ -123,6 +124,13 @@ namespace Module.Inspector.Editor.Utilities if (prop != null) validators.Add(new ResultValue(validator, prop)); } + else if (att is HandleDrawerPropertyAttribute handleDrawer) + { + var prop = InternalCreateInstanceOf(handleDrawer); + + if (prop != null) + handleDrawers.Add(new ResultValue(handleDrawer, prop)); + } else if (att is TooltipAttribute attTooltip) { tooltip = attTooltip.tooltip; @@ -139,9 +147,9 @@ namespace Module.Inspector.Editor.Utilities if (string.IsNullOrEmpty(obsoleteText)) { if (tooltip != null) - tooltip += $"\n[Obsolete]"; + tooltip += "\n[Obsolete]"; else - tooltip = $"[Obsolete]"; + tooltip = "[Obsolete]"; } else { @@ -152,9 +160,9 @@ namespace Module.Inspector.Editor.Utilities } } - return new Result(drawer, predrawerModifiers, valueModifiers, accessModifiers, validators, tooltip, isObsolete); + return new Result(drawer, predrawerModifiers, valueModifiers, accessModifiers, validators, handleDrawers, tooltip, isObsolete); } - + private static T InternalCreateInstanceOf(AbstractPropertyAttribute att) where T : AbstractPropertyDrawer { if (CACHED_ATT_TO_DRAWER.TryGetValue(att.GetType(), out Type drawerType)) @@ -181,6 +189,7 @@ namespace Module.Inspector.Editor.Utilities public readonly List> valueModifiers; public readonly List> accessModifiers; public readonly List> validators; + public readonly List> handleDrawers; public readonly string tooltip; public readonly bool isObsolete; @@ -189,6 +198,7 @@ namespace Module.Inspector.Editor.Utilities List> valueModifiers, List> accessModifiers, List> validators, + List> handleDrawers, string tooltip, bool isObsolete) { @@ -197,6 +207,7 @@ namespace Module.Inspector.Editor.Utilities this.valueModifiers = valueModifiers; this.accessModifiers = accessModifiers; this.validators = validators; + this.handleDrawers = handleDrawers; this.tooltip = tooltip; this.isObsolete = isObsolete; } @@ -244,6 +255,17 @@ namespace Module.Inspector.Editor.Utilities return null; } + + public T GetHandleDrawer() where T : HandleDrawerPropertyAttribute + { + for (var i = 0; i < handleDrawers.Count; i++) + { + if (handleDrawers[i].attribute is T att) + return att; + } + + return null; + } } /// diff --git a/README.md b/README.md index 6b488b1..eca2c5d 100644 --- a/README.md +++ b/README.md @@ -176,4 +176,31 @@ To allow fields hidden from inspector either by `NonSerialized` or `HideInInspec * `EnableShowHiddenFields` * Enables an additional search to find any "hidden" fields and draw them below `DefaultInspector` * `ShowHiddenField` - * Optional attribute for fields, if `EnableShowHiddenFields` has parameter `true` \ No newline at end of file + * Optional attribute for fields, if `EnableShowHiddenFields` has parameter `true` + + + +## Handles + +List of all handle attributes: + +* `BoxHandle` + * Resize a box shaped value, like Vector3 + * Optional: Provide a `fieldPosition` and/or `fieldRotation` for handles to position and rotate +* `CircleHandle` + * Resize a circle shaped value, like float + * Optional: Provide a `fieldPosition` for handle to position +* `LabelHandle` + * Write text or field values + * Optional: Provide a `fieldPosition` and/or `fieldRotation` for handles to position and rotate +* `PositionHandle` + * Position handle with option to set number of axis visible (X, Y, Z) +* `RectangleHandle` + * Resize a rectangle shaped value, like Vector2 + * Optional: Provide a `fieldPosition` and/or `fieldRotation` for handles to position and rotate +* `RotationHandle` + * Rotation handle for world or self-spaced rotation + * Optional: Provide a `fieldPosition` for handle to position +* `SphereHandle` + * Resize a sphere shaped value, like float + * Optional: Provide a `fieldPosition` and/or `fieldRotation` for handles to position and rotate diff --git a/Runtime/Enums/EAxis.cs b/Runtime/Enums/EAxis.cs new file mode 100644 index 0000000..feed0d1 --- /dev/null +++ b/Runtime/Enums/EAxis.cs @@ -0,0 +1,14 @@ +using System; + +namespace Module.Inspector +{ + [Flags] + public enum EAxis + { + None = 0, + X = 1, + Y = 2, + Z = 4, + All = X | Y | Z + } +} \ No newline at end of file diff --git a/Runtime/Enums/EAxis.cs.meta b/Runtime/Enums/EAxis.cs.meta new file mode 100644 index 0000000..c1744a1 --- /dev/null +++ b/Runtime/Enums/EAxis.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6cea1a74f79c4b4e98b10fe9b98a0cfe +timeCreated: 1669408493 \ No newline at end of file diff --git a/Runtime/Enums/ELabelType.cs b/Runtime/Enums/ELabelType.cs new file mode 100644 index 0000000..5aa0db6 --- /dev/null +++ b/Runtime/Enums/ELabelType.cs @@ -0,0 +1,12 @@ +using System; + +namespace Module.Inspector +{ + [Flags] + public enum ELabelType + { + None = 0, + Field = 1, + Value = 2 + } +} \ No newline at end of file diff --git a/Runtime/Enums/ELabelType.cs.meta b/Runtime/Enums/ELabelType.cs.meta new file mode 100644 index 0000000..2f3edcf --- /dev/null +++ b/Runtime/Enums/ELabelType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 00491187b70e400eb9bd403b49428b09 +timeCreated: 1669499298 \ No newline at end of file diff --git a/Runtime/Enums/EPropertyType.cs b/Runtime/Enums/EPropertyType.cs index 9b9f122..d807e99 100644 --- a/Runtime/Enums/EPropertyType.cs +++ b/Runtime/Enums/EPropertyType.cs @@ -6,6 +6,7 @@ Drawer, ValueModifier, AccessModifier, + HandleDrawer, Validate } } \ No newline at end of file diff --git a/Runtime/HandleDrawerPropertyAttribute.cs b/Runtime/HandleDrawerPropertyAttribute.cs new file mode 100644 index 0000000..5e2b549 --- /dev/null +++ b/Runtime/HandleDrawerPropertyAttribute.cs @@ -0,0 +1,7 @@ +namespace Module.Inspector +{ + public abstract class HandleDrawerPropertyAttribute : AbstractPropertyAttribute + { + public override EPropertyType Type => EPropertyType.HandleDrawer; + } +} \ No newline at end of file diff --git a/Runtime/HandleDrawerPropertyAttribute.cs.meta b/Runtime/HandleDrawerPropertyAttribute.cs.meta new file mode 100644 index 0000000..c2e04e7 --- /dev/null +++ b/Runtime/HandleDrawerPropertyAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f9cdb8b0deb04fde8fa9b56e03a6f8c8 +timeCreated: 1669408378 \ No newline at end of file diff --git a/Runtime/HandleDrawers.meta b/Runtime/HandleDrawers.meta new file mode 100644 index 0000000..4bc5581 --- /dev/null +++ b/Runtime/HandleDrawers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6f0c558105634558964c91d5d8e3c979 +timeCreated: 1669408405 \ No newline at end of file diff --git a/Runtime/HandleDrawers/BoxHandleAttribute.cs b/Runtime/HandleDrawers/BoxHandleAttribute.cs new file mode 100644 index 0000000..54272e8 --- /dev/null +++ b/Runtime/HandleDrawers/BoxHandleAttribute.cs @@ -0,0 +1,22 @@ +using System; +using UnityEngine; + +namespace Module.Inspector +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class BoxHandleAttribute : HandleDrawerPropertyAttribute + { + public readonly string fieldPosition; + public readonly string fieldRotation; + public readonly Space space; + + public BoxHandleAttribute(string fieldPosition = null, + string fieldRotation = null, + Space space = Space.World) + { + this.fieldPosition = fieldPosition; + this.fieldRotation = fieldRotation; + this.space = space; + } + } +} \ No newline at end of file diff --git a/Runtime/HandleDrawers/BoxHandleAttribute.cs.meta b/Runtime/HandleDrawers/BoxHandleAttribute.cs.meta new file mode 100644 index 0000000..9502811 --- /dev/null +++ b/Runtime/HandleDrawers/BoxHandleAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b2966619dc0e480480c69602eb4d25f4 +timeCreated: 1669475646 \ No newline at end of file diff --git a/Runtime/HandleDrawers/CircleHandleAttribute.cs b/Runtime/HandleDrawers/CircleHandleAttribute.cs new file mode 100644 index 0000000..a9218d4 --- /dev/null +++ b/Runtime/HandleDrawers/CircleHandleAttribute.cs @@ -0,0 +1,22 @@ +using System; +using UnityEngine; + +namespace Module.Inspector +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class CircleHandleAttribute : HandleDrawerPropertyAttribute + { + public readonly string fieldPosition; + public readonly string fieldRotation; + public readonly Space space; + + public CircleHandleAttribute(string fieldPosition = null, + string fieldRotation = null, + Space space = Space.World) + { + this.fieldPosition = fieldPosition; + this.fieldRotation = fieldRotation; + this.space = space; + } + } +} \ No newline at end of file diff --git a/Runtime/HandleDrawers/CircleHandleAttribute.cs.meta b/Runtime/HandleDrawers/CircleHandleAttribute.cs.meta new file mode 100644 index 0000000..e2a37c2 --- /dev/null +++ b/Runtime/HandleDrawers/CircleHandleAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ec1137ba9e1344398415c1874809f64b +timeCreated: 1669475438 \ No newline at end of file diff --git a/Runtime/HandleDrawers/LabelHandleAttribute.cs b/Runtime/HandleDrawers/LabelHandleAttribute.cs new file mode 100644 index 0000000..109ecd3 --- /dev/null +++ b/Runtime/HandleDrawers/LabelHandleAttribute.cs @@ -0,0 +1,22 @@ +using System; +using UnityEngine; + +namespace Module.Inspector +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class LabelHandleAttribute : HandleDrawerPropertyAttribute + { + public readonly ELabelType type; + public readonly string fieldPosition; + public readonly Space space; + + public LabelHandleAttribute(ELabelType type = ELabelType.Value, + string fieldPosition = null, + Space space = Space.World) + { + this.type = type; + this.fieldPosition = fieldPosition; + this.space = space; + } + } +} \ No newline at end of file diff --git a/Runtime/HandleDrawers/LabelHandleAttribute.cs.meta b/Runtime/HandleDrawers/LabelHandleAttribute.cs.meta new file mode 100644 index 0000000..762ef2f --- /dev/null +++ b/Runtime/HandleDrawers/LabelHandleAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b04dcda9e8db4bfcab1d02ca1a7904f4 +timeCreated: 1669475765 \ No newline at end of file diff --git a/Runtime/HandleDrawers/PositionHandleAttribute.cs b/Runtime/HandleDrawers/PositionHandleAttribute.cs new file mode 100644 index 0000000..3b8ea93 --- /dev/null +++ b/Runtime/HandleDrawers/PositionHandleAttribute.cs @@ -0,0 +1,18 @@ +using System; +using UnityEngine; + +namespace Module.Inspector +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class PositionHandleAttribute : HandleDrawerPropertyAttribute + { + public readonly Space space; + public readonly EAxis axiis; + + public PositionHandleAttribute(Space space, EAxis axiis) + { + this.space = space; + this.axiis = axiis; + } + } +} \ No newline at end of file diff --git a/Runtime/HandleDrawers/PositionHandleAttribute.cs.meta b/Runtime/HandleDrawers/PositionHandleAttribute.cs.meta new file mode 100644 index 0000000..b545c59 --- /dev/null +++ b/Runtime/HandleDrawers/PositionHandleAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6ee82f8e6bfe42cd96c84a910b716d7a +timeCreated: 1669408436 \ No newline at end of file diff --git a/Runtime/HandleDrawers/RectangleHandleAttribute.cs b/Runtime/HandleDrawers/RectangleHandleAttribute.cs new file mode 100644 index 0000000..db4106f --- /dev/null +++ b/Runtime/HandleDrawers/RectangleHandleAttribute.cs @@ -0,0 +1,22 @@ +using System; +using UnityEngine; + +namespace Module.Inspector +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class RectangleHandleAttribute : HandleDrawerPropertyAttribute + { + public readonly string fieldPosition; + public readonly string fieldRotation; + public readonly Space space; + + public RectangleHandleAttribute(string fieldPosition = null, + string fieldRotation = null, + Space space = Space.World) + { + this.fieldPosition = fieldPosition; + this.fieldRotation = fieldRotation; + this.space = space; + } + } +} \ No newline at end of file diff --git a/Runtime/HandleDrawers/RectangleHandleAttribute.cs.meta b/Runtime/HandleDrawers/RectangleHandleAttribute.cs.meta new file mode 100644 index 0000000..8ab0207 --- /dev/null +++ b/Runtime/HandleDrawers/RectangleHandleAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c0b65d01ae7944ababe1c42a9497192c +timeCreated: 1669475700 \ No newline at end of file diff --git a/Runtime/HandleDrawers/RotationHandleAttribute.cs b/Runtime/HandleDrawers/RotationHandleAttribute.cs new file mode 100644 index 0000000..788a378 --- /dev/null +++ b/Runtime/HandleDrawers/RotationHandleAttribute.cs @@ -0,0 +1,18 @@ +using System; +using UnityEngine; + +namespace Module.Inspector +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class RotationHandleAttribute : HandleDrawerPropertyAttribute + { + public readonly string fieldPosition; + public readonly Space space; + + public RotationHandleAttribute(string fieldPosition = null, Space space = Space.World) + { + this.fieldPosition = fieldPosition; + this.space = space; + } + } +} \ No newline at end of file diff --git a/Runtime/HandleDrawers/RotationHandleAttribute.cs.meta b/Runtime/HandleDrawers/RotationHandleAttribute.cs.meta new file mode 100644 index 0000000..8e874ba --- /dev/null +++ b/Runtime/HandleDrawers/RotationHandleAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0a51649ba7d643b59166944db5f2dc95 +timeCreated: 1669475570 \ No newline at end of file diff --git a/Runtime/HandleDrawers/SphereHandleAttribute.cs b/Runtime/HandleDrawers/SphereHandleAttribute.cs new file mode 100644 index 0000000..5fb79bd --- /dev/null +++ b/Runtime/HandleDrawers/SphereHandleAttribute.cs @@ -0,0 +1,22 @@ +using System; +using UnityEngine; + +namespace Module.Inspector +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class SphereHandleAttribute : HandleDrawerPropertyAttribute + { + public readonly string fieldPosition; + public readonly string fieldRotation; + public readonly Space space; + + public SphereHandleAttribute(string fieldPosition = null, + string fieldRotation = null, + Space space = Space.World) + { + this.fieldPosition = fieldPosition; + this.fieldRotation = fieldRotation; + this.space = space; + } + } +} \ No newline at end of file diff --git a/Runtime/HandleDrawers/SphereHandleAttribute.cs.meta b/Runtime/HandleDrawers/SphereHandleAttribute.cs.meta new file mode 100644 index 0000000..d9e6077 --- /dev/null +++ b/Runtime/HandleDrawers/SphereHandleAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4ec43235833844159723030f304ac03b +timeCreated: 1669475530 \ No newline at end of file diff --git a/package.json b/package.json index ef26098..9a85081 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.module.inspector", - "version": "1.8.4", + "version": "1.9.0", "displayName": "Module.Inspector", "description": "Custom inspector with various useful property drawers", "unity": "2019.2",