Files
aibis-dream/Assets/Shapes/Scripts/Editor/Utils/SceneRectEditor.cs
T
2025-05-07 15:07:44 +08:00

160 lines
5.8 KiB
C#

using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
// Shapes © Freya Holmér - https://twitter.com/FreyaHolmer/
// Website & Documentation - https://acegikmo.com/shapes/
namespace Shapes {
public class SceneRectEditor : SceneEditGizmos {
static bool isEditing;
BoxBoundsHandle boxHandle = ShapesHandles.InitBoxHandle();
public SceneRectEditor( Editor parentEditor ) => this.parentEditor = parentEditor;
protected override bool IsEditing {
get => isEditing;
set => isEditing = value;
}
public bool DoSceneHandles( Rectangle rect ) {
if( IsEditing == false )
return false;
bool holdingAlt = ( Event.current.modifiers & EventModifiers.Alt ) != 0;
bool showControls = holdingAlt == false;
// set up matrix
Matrix4x4 gizmoToWorld = Matrix4x4.TRS( default, rect.transform.rotation, Vector3.one );
Matrix4x4 worldToGizmo = gizmoToWorld.inverse;
Vector2 GizmoToRect( Vector3 gizmoPt ) {
Vector3 wPos = gizmoToWorld.MultiplyPoint( gizmoPt );
return rect.transform.InverseTransformPoint( wPos );
}
Vector3 RectToGizmo( Vector2 rectPt ) {
Vector3 wPos = rect.transform.TransformPoint( rectPt );
return worldToGizmo.MultiplyPoint( wPos );
}
Vector2 GizmoToRectVec( Vector3 gizmoPt ) {
Vector3 wPos = gizmoToWorld.MultiplyVector( gizmoPt );
return rect.transform.InverseTransformVector( wPos );
}
Vector3 RectToGizmoVec( Vector2 rectPt ) {
Vector3 wPos = rect.transform.TransformVector( rectPt );
return worldToGizmo.MultiplyVector( wPos );
}
Vector2 GetCenter() => GizmoToRect( boxHandle.center );
Vector2 GetSize() => GizmoToRectVec( boxHandle.size );
Vector2 GetBottomLeft() => GetCenter() - GetSize() / 2;
Vector2 RectCenter() => rect.Pivot == RectPivot.Center ? Vector2.zero : RectSize() / 2;
Vector2 RectSize() => new Vector2( rect.Width, rect.Height );
Vector2 RectBottomLeft() => RectCenter() - RectSize() / 2;
using( new Handles.DrawingScope( ShapesHandles.GetHandleColor( rect.Color ), gizmoToWorld ) ) {
boxHandle.size = RectToGizmoVec( new Vector2( rect.Width, rect.Height ) );
boxHandle.center = RectToGizmo( RectCenter() );
Vector2 prevBottomLeft = GetBottomLeft();
using( var chchk = new EditorGUI.ChangeCheckScope() ) {
boxHandle.DrawHandle();
if( chchk.changed ) {
Undo.RecordObject( rect, "edit rectangle" );
Vector2 newSize = GetSize();
rect.Width = newSize.x;
rect.Height = newSize.y;
if( rect.Pivot == RectPivot.Corner ) {
Transform rtf = rect.transform;
Undo.RecordObject( rtf, "edit rectangle" );
Vector2 newBottomLeft = GetBottomLeft();
Vector2 delta = newBottomLeft - prevBottomLeft;
Transform parent = rtf.parent;
Vector3 deltaWorld = rtf.TransformVector( delta );
Vector3 deltaParent = parent != null ? parent.InverseTransformVector( deltaWorld ) : deltaWorld;
rtf.localPosition += deltaParent;
}
return true;
}
}
if( rect.IsRounded ) {
Vector3 gizUp = RectToGizmoVec( Vector3.up );
Vector3 gizRight = RectToGizmoVec( Vector3.right );
Vector3 gizLeft = -gizRight;
Vector3 gizDown = -gizUp;
( Vector3 a, Vector3 b )[] gizDirs = {
( gizRight, gizUp ),
( gizDown, gizRight ),
( gizLeft, gizDown ),
( gizUp, gizLeft )
};
Vector2 rectBl = RectBottomLeft();
Vector3[] gizCorners = {
RectToGizmo( rectBl ),
RectToGizmo( rectBl + Vector2.up * rect.Height ),
RectToGizmo( rectBl + Vector2.up * rect.Height + Vector2.right * rect.Width ),
RectToGizmo( rectBl + Vector2.right * rect.Width )
};
float maxRadius = Mathf.Min( rect.Width, rect.Height ) / 2f;
for( int i = 0; i < 4; i++ ) {
float prevRadius = rect.CornerRadiusMode == Rectangle.RectangleCornerRadiusMode.Uniform ? rect.CornerRadius : rect.CornerRadii[i];
float radiusGizmoSpace = RectToGizmoVec( prevRadius * Vector2.one ).x;
Vector3 cornerGizmoSpace = gizCorners[i];
// markers
Vector3 innerCornerGizmoSpace = cornerGizmoSpace + ( gizDirs[i].a + gizDirs[i].b ) * radiusGizmoSpace;
Handles.DrawWireArc( innerCornerGizmoSpace, Vector3.forward, -gizDirs[i].a, 90f, radiusGizmoSpace );
using( new Handles.DrawingScope( new Color( Handles.color.r, Handles.color.g, Handles.color.b, 0.5f ) ) ) {
Handles.DrawLine( innerCornerGizmoSpace, cornerGizmoSpace + gizDirs[i].a * radiusGizmoSpace );
Handles.DrawLine( innerCornerGizmoSpace, cornerGizmoSpace + gizDirs[i].b * radiusGizmoSpace );
}
Handles.DrawLine( innerCornerGizmoSpace, innerCornerGizmoSpace - ( gizDirs[i].a + gizDirs[i].b ) * radiusGizmoSpace / Mathf.Sqrt( 2 ) );
//Handles.DrawWireDisc( cornerGizmoSpace + (gizDirs[i].a + gizDirs[i].b ) * radiusGizmoSpace, Vector3.forward, prevRadius );
if( showControls == false )
continue;
using( var chchk = new EditorGUI.ChangeCheckScope() ) {
Vector3 handlePos = innerCornerGizmoSpace;
float size = HandleUtility.GetHandleSize( handlePos ) * 0.15f;
Vector3 gizDir = gizDirs[i].a + gizDirs[i].b; // diagonal
Vector3 newPosGizmoSpace = Handles.Slider( handlePos, gizDir, size, Handles.CubeHandleCap, 0f );
if( chchk.changed ) {
Undo.RecordObject( rect, "edit rectangle corner radius" );
Vector3 deltaGizmoSpace = newPosGizmoSpace - cornerGizmoSpace;
float newRadius = Mathf.Abs( GizmoToRectVec( deltaGizmoSpace ).x );
if( rect.CornerRadiusMode == Rectangle.RectangleCornerRadiusMode.Uniform ) {
rect.CornerRadius = Mathf.Min( newRadius, maxRadius );
} else {
Vector4 radii = rect.CornerRadii;
radii[i] = Mathf.Min( newRadius, maxRadius );
rect.CornerRadii = radii;
}
return true;
}
}
}
}
}
return false;
}
}
}