445 lines
10 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|