Skip to content

Instantly share code, notes, and snippets.

@simonwittber
Created May 14, 2025 02:58
Show Gist options
  • Save simonwittber/38db5d079b41246d7e043dae00f8a2e5 to your computer and use it in GitHub Desktop.
Save simonwittber/38db5d079b41246d7e043dae00f8a2e5 to your computer and use it in GitHub Desktop.
Handle for resizing rects in Unity.
using UnityEditor;
using UnityEngine;
public class RectBoundsHandle
{
public float HandleSize = 10f;
public float CornerGrabRadius = 12f;
public Color FillColor = new Color(0, 1, 1, 0.1f);
public Color OutlineColor = Color.cyan;
public Color HandleColor = Color.blue;
// internal state
Corner _activeCorner = Corner.None;
private Vector2 _initialPosition;
private Vector2 _dragOffset;
enum Corner
{
None = -1,
TopLeft,
TopRight,
BottomRight,
BottomLeft,
Top,
Right,
Bottom,
Left,
Center
}
public Rect DrawHandle(Rect rect)
{
var rectCopy = rect;
var e = Event.current;
// Draw fill + outline
Handles.DrawSolidRectangleWithOutline(rect, FillColor, OutlineColor);
var corners = new[]
{
(Corner.TopLeft, MouseCursor.ResizeUpLeft, new Vector2(rect.xMin, rect.yMin)), // top-left
(Corner.TopRight, MouseCursor.ResizeUpRight, new Vector2(rect.xMax, rect.yMin)), // top-right
(Corner.BottomRight, MouseCursor.ResizeUpLeft, new Vector2(rect.xMax, rect.yMax)), // bottom-right
(Corner.BottomLeft, MouseCursor.ResizeUpRight, new Vector2(rect.xMin, rect.yMax)), // bottom-left
(Corner.Top, MouseCursor.ResizeVertical, new Vector2(rect.center.x, rect.yMin)), // top
(Corner.Right, MouseCursor.ResizeHorizontal, new Vector2(rect.xMax, rect.center.y)), // right
(Corner.Bottom, MouseCursor.ResizeVertical, new Vector2(rect.center.x, rect.yMax)), // bottom
(Corner.Left, MouseCursor.ResizeHorizontal, new Vector2(rect.xMin, rect.center.y)), // left
(Corner.Center, MouseCursor.MoveArrow, new Vector2(rect.center.x, rect.center.y)) // center
};
foreach(var (corner, cursor, cpos) in corners)
{
var hr = new Rect(cpos.x - HandleSize / 2, cpos.y - HandleSize / 2, HandleSize, HandleSize);
Handles.color = HandleColor;
Handles.DrawSolidDisc(cpos, Vector3.forward, HandleSize / 2);
Handles.color = Color.white;
EditorGUIUtility.AddCursorRect(hr, cursor);
}
switch (e.type)
{
case EventType.MouseDown when e.button == 0:
// see if we hit a corner
foreach(var (corner, cursor, cpos) in corners)
{
if (Vector2.Distance(e.mousePosition, cpos) < CornerGrabRadius / 2)
{
_activeCorner = corner;
_initialPosition = cpos;
_dragOffset = cpos - e.mousePosition;
e.Use();
return rect;
}
}
break;
case EventType.MouseDrag when e.button == 0:
var delta = e.mousePosition - _initialPosition;
if (_activeCorner >= 0)
{
// resize from that corner
var newCornerPos = (_initialPosition + _dragOffset) + delta;
switch (_activeCorner)
{
case Corner.TopLeft:
rect.xMin = newCornerPos.x;
rect.yMin = newCornerPos.y;
break;
case Corner.TopRight:
rect.xMax = newCornerPos.x;
rect.yMin = newCornerPos.y;
break;
case Corner.BottomRight:
rect.xMax = newCornerPos.x;
rect.yMax = newCornerPos.y;
break;
case Corner.BottomLeft:
rect.xMin = newCornerPos.x;
rect.yMax = newCornerPos.y;
break;
case Corner.Top:
rect.yMin = newCornerPos.y;
break;
case Corner.Right:
rect.xMax = newCornerPos.x;
break;
case Corner.Bottom:
rect.yMax = newCornerPos.y;
break;
case Corner.Left:
rect.xMin = newCornerPos.x;
break;
case Corner.Center:
rect.center = newCornerPos;
break;
}
e.Use();
}
break;
case EventType.MouseUp when e.button == 0:
_activeCorner = Corner.None;
break;
}
return rect;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment