module-inspector/Editor/Utilities/EditorHandleUtility.cs

470 lines
20 KiB
C#

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;
}
}
}
}