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() ?? base.gameObject.AddComponent(); } return layoutElement; } } private void Start() { HorizontalOrVerticalLayoutGroup component = GetComponent(); 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(); } 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; } } }