Files
2026-02-21 16:45:37 +08:00

445 lines
10 KiB
C#

using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace UIWidgets
{
public class Resizable : MonoBehaviour, IInitializePotentialDragHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IEventSystemHandler
{
[Serializable]
public struct Directions
{
public bool Top;
public bool Bottom;
public bool Left;
public bool Right;
public Directions(bool top, bool bottom, bool left, bool right)
{
Top = top;
Bottom = bottom;
Left = left;
Right = right;
}
}
public struct Regions
{
public bool Top;
public bool Bottom;
public bool Left;
public bool Right;
public bool NWSE
{
get
{
return (Top && Left) || (Bottom && Right);
}
}
public bool NESW
{
get
{
return (Top && Right) || (Bottom && Left);
}
}
public bool NS
{
get
{
return (Top && !Right) || (Bottom && !Left);
}
}
public bool EW
{
get
{
return (!Top && Right) || (!Bottom && Left);
}
}
public bool Active
{
get
{
return Top || Bottom || Left || Right;
}
}
public void Reset()
{
Top = false;
Bottom = false;
Left = false;
Right = false;
}
public override string ToString()
{
return string.Format("Top: {0}; Bottom: {1}; Left: {2}; Right: {3}", Top, Bottom, Left, Right);
}
}
[SerializeField]
public bool UpdateRectTransform = true;
[SerializeField]
public bool UpdateLayoutElement = true;
[SerializeField]
[Tooltip("Maximum padding from border where resize active.")]
public float ActiveRegion = 5f;
[SerializeField]
public Vector2 MinSize;
[Tooltip("Set 0 to unlimit.")]
[SerializeField]
public Vector2 MaxSize;
[SerializeField]
public bool KeepAspectRatio;
[SerializeField]
public Directions ResizeDirections = new Directions(true, true, true, true);
[SerializeField]
public Camera CurrentCamera;
[SerializeField]
public Texture2D CursorEWTexture;
[SerializeField]
public Vector2 CursorEWHotSpot = new Vector2(16f, 16f);
[SerializeField]
public Texture2D CursorNSTexture;
[SerializeField]
public Vector2 CursorNSHotSpot = new Vector2(16f, 16f);
[SerializeField]
public Texture2D CursorNESWTexture;
[SerializeField]
public Vector2 CursorNESWHotSpot = new Vector2(16f, 16f);
[SerializeField]
public Texture2D CursorNWSETexture;
[SerializeField]
public Vector2 CursorNWSEHotSpot = new Vector2(16f, 16f);
[SerializeField]
public Texture2D DefaultCursorTexture;
[SerializeField]
public Vector2 DefaultCursorHotSpot;
public ResizableEvent OnStartResize = new ResizableEvent();
public ResizableEvent OnEndResize = new ResizableEvent();
private RectTransform rectTransform;
private LayoutElement layoutElement;
private Regions regions;
private Regions dragRegions;
private Canvas canvas;
private RectTransform canvasRect;
private bool processDrag;
private static bool globalCursorSetted;
private bool cursorSetted;
public RectTransform RectTransform
{
get
{
if (rectTransform == null)
{
rectTransform = base.transform as RectTransform;
}
return rectTransform;
}
}
public LayoutElement LayoutElement
{
get
{
if (layoutElement == null)
{
layoutElement = GetComponent<LayoutElement>() ?? base.gameObject.AddComponent<LayoutElement>();
}
return layoutElement;
}
}
private void Start()
{
HorizontalOrVerticalLayoutGroup component = GetComponent<HorizontalOrVerticalLayoutGroup>();
if ((bool)component)
{
Utilites.UpdateLayout(component);
}
Init();
}
public void OnInitializePotentialDrag(PointerEventData eventData)
{
Init();
}
public void Init()
{
canvasRect = Utilites.FindCanvas(base.transform) as RectTransform;
canvas = canvasRect.GetComponent<Canvas>();
}
private void LateUpdate()
{
globalCursorSetted = false;
Vector2 localPoint;
if ((!globalCursorSetted || cursorSetted) && !processDrag && Input.mousePresent && RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, Input.mousePosition, CurrentCamera, out localPoint))
{
if (!RectTransform.rect.Contains(localPoint))
{
regions.Reset();
UpdateCursor();
}
else
{
UpdateRegions(localPoint);
UpdateCursor();
}
}
}
private void UpdateRegions(Vector2 point)
{
regions.Top = ResizeDirections.Top && CheckTop(point);
regions.Bottom = ResizeDirections.Bottom && CheckBottom(point);
regions.Left = ResizeDirections.Left && CheckLeft(point);
regions.Right = ResizeDirections.Right && CheckRight(point);
}
private void UpdateCursor()
{
if (regions.NWSE)
{
globalCursorSetted = true;
cursorSetted = true;
Cursor.SetCursor(CursorNWSETexture, CursorNWSEHotSpot, Utilites.GetCursorMode());
}
else if (regions.NESW)
{
globalCursorSetted = true;
cursorSetted = true;
Cursor.SetCursor(CursorNESWTexture, CursorNESWHotSpot, Utilites.GetCursorMode());
}
else if (regions.NS)
{
globalCursorSetted = true;
cursorSetted = true;
Cursor.SetCursor(CursorNSTexture, CursorNSHotSpot, Utilites.GetCursorMode());
}
else if (regions.EW)
{
globalCursorSetted = true;
cursorSetted = true;
Cursor.SetCursor(CursorEWTexture, CursorEWHotSpot, Utilites.GetCursorMode());
}
else if (cursorSetted)
{
globalCursorSetted = false;
cursorSetted = false;
Cursor.SetCursor(DefaultCursorTexture, DefaultCursorHotSpot, Utilites.GetCursorMode());
}
}
private bool CheckTop(Vector2 point)
{
Rect rect = RectTransform.rect;
rect.position = new Vector2(rect.position.x, rect.position.y + rect.height - ActiveRegion);
rect.height = ActiveRegion;
return rect.Contains(point);
}
private bool CheckBottom(Vector2 point)
{
Rect rect = RectTransform.rect;
rect.height = ActiveRegion;
return rect.Contains(point);
}
private bool CheckLeft(Vector2 point)
{
Rect rect = RectTransform.rect;
rect.width = ActiveRegion;
return rect.Contains(point);
}
private bool CheckRight(Vector2 point)
{
Rect rect = RectTransform.rect;
rect.position = new Vector2(rect.position.x + rect.width - ActiveRegion, rect.position.y);
rect.width = ActiveRegion;
return rect.Contains(point);
}
public void OnBeginDrag(PointerEventData eventData)
{
processDrag = false;
Vector2 localPoint;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.pressPosition, eventData.pressEventCamera, out localPoint))
{
UpdateRegions(localPoint);
processDrag = regions.Active;
dragRegions = regions;
UpdateCursor();
LayoutElement.preferredHeight = RectTransform.rect.height;
LayoutElement.preferredWidth = RectTransform.rect.width;
OnStartResize.Invoke(this);
}
}
private void ResetCursor()
{
globalCursorSetted = false;
cursorSetted = false;
Cursor.SetCursor(DefaultCursorTexture, DefaultCursorHotSpot, Utilites.GetCursorMode());
}
public void OnEndDrag(PointerEventData eventData)
{
ResetCursor();
processDrag = false;
OnEndResize.Invoke(this);
}
public void OnDrag(PointerEventData eventData)
{
if (processDrag)
{
if (canvas == null)
{
throw new MissingComponentException(base.gameObject.name + " not in Canvas hierarchy.");
}
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position, CurrentCamera, out localPoint);
Vector2 localPoint2;
RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position - eventData.delta, CurrentCamera, out localPoint2);
Vector2 delta = localPoint - localPoint2;
if (UpdateRectTransform)
{
PerformUpdateRectTransform(delta);
}
if (UpdateLayoutElement)
{
PerformUpdateLayoutElement(delta);
}
}
}
private void PerformUpdateRectTransform(Vector2 delta)
{
Vector2 pivot = RectTransform.pivot;
Vector2 vector = RectTransform.rect.size;
Vector2 vector2 = vector;
Vector2 vector3 = new Vector2(1f, 1f);
if (dragRegions.Left || dragRegions.Right)
{
vector3.x = (dragRegions.Right ? 1 : (-1));
vector.x = Mathf.Max(MinSize.x, vector.x + vector3.x * delta.x);
if (MaxSize.x != 0f)
{
vector.x = Mathf.Min(MaxSize.x, vector.x);
}
}
if (dragRegions.Top || dragRegions.Bottom)
{
vector3.y = (dragRegions.Top ? 1 : (-1));
vector.y = Mathf.Max(MinSize.y, vector.y + vector3.y * delta.y);
if (MaxSize.y != 0f)
{
vector.y = Mathf.Min(MaxSize.y, vector.y);
}
}
if (KeepAspectRatio)
{
vector = FixAspectRatio(vector, vector2);
}
Vector2 vector4 = new Vector2((!dragRegions.Right) ? (pivot.x - 1f) : pivot.x, (!dragRegions.Top) ? (pivot.y - 1f) : pivot.y);
Vector2 vector5 = vector - vector2;
vector5 = new Vector2(vector5.x * vector4.x, vector5.y * vector4.y);
RectTransform.anchoredPosition += vector5;
RectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, vector.x);
RectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, vector.y);
}
protected Vector2 FixAspectRatio(Vector2 newSize, Vector2 baseSize)
{
Vector2 result = newSize;
float num = baseSize.x / baseSize.y;
Vector2 vector = new Vector2(Mathf.Abs(newSize.x - baseSize.x), Mathf.Abs(newSize.y - baseSize.y));
if (vector.x >= vector.y)
{
result.y = result.x / num;
}
else
{
result.x = result.y * num;
}
return result;
}
private void PerformUpdateLayoutElement(Vector2 delta)
{
Vector2 vector = new Vector2(LayoutElement.preferredWidth, LayoutElement.preferredHeight);
Vector2 baseSize = vector;
if (dragRegions.Left || dragRegions.Right)
{
int num = (dragRegions.Right ? 1 : (-1));
float b = Mathf.Max(MinSize.x, LayoutElement.preferredWidth + (float)num * delta.x);
if (MaxSize.x != 0f)
{
vector.x = Mathf.Min(MaxSize.x, b);
}
}
if (dragRegions.Top || dragRegions.Bottom)
{
int num2 = (dragRegions.Top ? 1 : (-1));
float b2 = Mathf.Max(MinSize.y, LayoutElement.preferredHeight + (float)num2 * delta.y);
if (MaxSize.y != 0f)
{
vector.y = Mathf.Min(MaxSize.y, b2);
}
}
if (KeepAspectRatio)
{
vector = FixAspectRatio(vector, baseSize);
}
LayoutElement.preferredWidth = vector.x;
LayoutElement.preferredHeight = vector.y;
}
}
}