466 lines
12 KiB
C#
466 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
namespace UIWidgets
|
|
{
|
|
[RequireComponent(typeof(LayoutGroup))]
|
|
public class ResizableHeader : MonoBehaviour, IDropSupport<ResizableHeaderDragCell>
|
|
{
|
|
[SerializeField]
|
|
public ListViewBase List;
|
|
|
|
[SerializeField]
|
|
public bool AllowResize = true;
|
|
|
|
[SerializeField]
|
|
public bool AllowReorder = true;
|
|
|
|
[NonSerialized]
|
|
[HideInInspector]
|
|
public bool ProcessCellReorder;
|
|
|
|
[SerializeField]
|
|
public bool OnDragUpdate = true;
|
|
|
|
[SerializeField]
|
|
public float ActiveRegion = 5f;
|
|
|
|
[SerializeField]
|
|
public Camera CurrentCamera;
|
|
|
|
[SerializeField]
|
|
public Texture2D CursorTexture;
|
|
|
|
[SerializeField]
|
|
public Vector2 CursorHotSpot = new Vector2(16f, 16f);
|
|
|
|
[SerializeField]
|
|
public Texture2D AllowDropCursor;
|
|
|
|
[SerializeField]
|
|
public Vector2 AllowDropCursorHotSpot = new Vector2(4f, 2f);
|
|
|
|
[SerializeField]
|
|
public Texture2D DeniedDropCursor;
|
|
|
|
[SerializeField]
|
|
public Vector2 DeniedDropCursorHotSpot = new Vector2(4f, 2f);
|
|
|
|
[SerializeField]
|
|
public Texture2D DefaultCursorTexture;
|
|
|
|
[SerializeField]
|
|
public Vector2 DefaultCursorHotSpot;
|
|
|
|
private RectTransform rectTransform;
|
|
|
|
private Canvas canvas;
|
|
|
|
private RectTransform canvasRect;
|
|
|
|
private List<LayoutElement> childrenLayouts = new List<LayoutElement>();
|
|
|
|
private List<RectTransform> children = new List<RectTransform>();
|
|
|
|
private List<int> positions;
|
|
|
|
private LayoutElement leftTarget;
|
|
|
|
private LayoutElement rightTarget;
|
|
|
|
private bool processDrag;
|
|
|
|
private List<float> widths;
|
|
|
|
private LayoutGroup layout;
|
|
|
|
private bool inActiveRegion;
|
|
|
|
private float widthLimit;
|
|
|
|
private List<RaycastResult> raycastResults = new List<RaycastResult>();
|
|
|
|
public RectTransform RectTransform
|
|
{
|
|
get
|
|
{
|
|
if (rectTransform == null)
|
|
{
|
|
rectTransform = base.transform as RectTransform;
|
|
}
|
|
return rectTransform;
|
|
}
|
|
}
|
|
|
|
public bool InActiveRegion
|
|
{
|
|
get
|
|
{
|
|
return inActiveRegion;
|
|
}
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
layout = GetComponent<LayoutGroup>();
|
|
if (layout != null)
|
|
{
|
|
Utilites.UpdateLayout(layout);
|
|
}
|
|
Init();
|
|
}
|
|
|
|
public void OnInitializePotentialDrag(PointerEventData eventData)
|
|
{
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
canvasRect = Utilites.FindCanvas(base.transform) as RectTransform;
|
|
canvas = canvasRect.GetComponent<Canvas>();
|
|
children.Clear();
|
|
childrenLayouts.Clear();
|
|
int num = 0;
|
|
foreach (Transform item2 in base.transform)
|
|
{
|
|
LayoutElement item = item2.GetComponent<LayoutElement>() ?? item2.gameObject.AddComponent<LayoutElement>();
|
|
children.Add(item2 as RectTransform);
|
|
childrenLayouts.Add(item);
|
|
ResizableHeaderDragCell resizableHeaderDragCell = item2.gameObject.AddComponent<ResizableHeaderDragCell>();
|
|
resizableHeaderDragCell.Position = num;
|
|
resizableHeaderDragCell.ResizableHeader = this;
|
|
resizableHeaderDragCell.AllowDropCursor = AllowDropCursor;
|
|
resizableHeaderDragCell.AllowDropCursorHotSpot = AllowDropCursorHotSpot;
|
|
resizableHeaderDragCell.DeniedDropCursor = DeniedDropCursor;
|
|
resizableHeaderDragCell.DeniedDropCursorHotSpot = DeniedDropCursorHotSpot;
|
|
ResizableHeaderCell resizableHeaderCell = item2.gameObject.AddComponent<ResizableHeaderCell>();
|
|
resizableHeaderCell.OnInitializePotentialDragEvent.AddListener(OnInitializePotentialDrag);
|
|
resizableHeaderCell.OnBeginDragEvent.AddListener(OnBeginDrag);
|
|
resizableHeaderCell.OnDragEvent.AddListener(OnDrag);
|
|
resizableHeaderCell.OnEndDragEvent.AddListener(OnEndDrag);
|
|
num++;
|
|
}
|
|
positions = Enumerable.Range(0, num).ToList();
|
|
CalculateWidths();
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (AllowResize && !processDrag && !ProcessCellReorder && !(CursorTexture == null) && Input.mousePresent)
|
|
{
|
|
inActiveRegion = CheckInActiveRegion(Input.mousePosition, CurrentCamera);
|
|
if (inActiveRegion)
|
|
{
|
|
Cursor.SetCursor(CursorTexture, CursorHotSpot, Utilites.GetCursorMode());
|
|
}
|
|
else
|
|
{
|
|
Cursor.SetCursor(DefaultCursorTexture, DefaultCursorHotSpot, Utilites.GetCursorMode());
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool CheckInActiveRegion(Vector2 position, Camera currentCamera)
|
|
{
|
|
bool flag = false;
|
|
Vector2 localPoint;
|
|
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, position, currentCamera, out localPoint))
|
|
{
|
|
return false;
|
|
}
|
|
Rect rect = RectTransform.rect;
|
|
if (!rect.Contains(localPoint))
|
|
{
|
|
return false;
|
|
}
|
|
localPoint += new Vector2(rect.width * RectTransform.pivot.x, 0f);
|
|
int num = 0;
|
|
foreach (RectTransform child in children)
|
|
{
|
|
if (num != 0)
|
|
{
|
|
flag = CheckLeft(child, localPoint);
|
|
if (flag)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (num != children.Count - 1)
|
|
{
|
|
flag = CheckRight(child, localPoint);
|
|
if (flag)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
num++;
|
|
}
|
|
return flag;
|
|
}
|
|
|
|
public virtual void OnBeginDrag(PointerEventData eventData)
|
|
{
|
|
if (!AllowResize || ProcessCellReorder)
|
|
{
|
|
return;
|
|
}
|
|
processDrag = false;
|
|
Vector2 localPoint;
|
|
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.pressPosition, eventData.pressEventCamera, out localPoint))
|
|
{
|
|
return;
|
|
}
|
|
localPoint += new Vector2(RectTransform.rect.width * RectTransform.pivot.x, 0f);
|
|
int num = 0;
|
|
foreach (RectTransform child in children)
|
|
{
|
|
if (num != 0)
|
|
{
|
|
processDrag = CheckLeft(child, localPoint);
|
|
if (processDrag)
|
|
{
|
|
leftTarget = childrenLayouts[num - 1];
|
|
rightTarget = childrenLayouts[num];
|
|
widthLimit = children[num - 1].rect.width + children[num].rect.width;
|
|
break;
|
|
}
|
|
}
|
|
if (num != children.Count - 1)
|
|
{
|
|
processDrag = CheckRight(child, localPoint);
|
|
if (processDrag)
|
|
{
|
|
leftTarget = childrenLayouts[num];
|
|
rightTarget = childrenLayouts[num + 1];
|
|
widthLimit = children[num].rect.width + children[num + 1].rect.width;
|
|
break;
|
|
}
|
|
}
|
|
num++;
|
|
}
|
|
}
|
|
|
|
private bool CheckLeft(RectTransform childRectTransform, Vector2 point)
|
|
{
|
|
Rect rect = childRectTransform.rect;
|
|
rect.position += new Vector2(childRectTransform.anchoredPosition.x, 0f);
|
|
rect.width = ActiveRegion;
|
|
return rect.Contains(point);
|
|
}
|
|
|
|
private bool CheckRight(RectTransform childRectTransform, Vector2 point)
|
|
{
|
|
Rect rect = childRectTransform.rect;
|
|
rect.position += new Vector2(childRectTransform.anchoredPosition.x, 0f);
|
|
rect.position = new Vector2(rect.position.x + rect.width - ActiveRegion - 1f, rect.position.y);
|
|
rect.width = ActiveRegion + 1f;
|
|
return rect.Contains(point);
|
|
}
|
|
|
|
public void OnEndDrag(PointerEventData eventData)
|
|
{
|
|
if (processDrag)
|
|
{
|
|
Cursor.SetCursor(DefaultCursorTexture, DefaultCursorHotSpot, Utilites.GetCursorMode());
|
|
CalculateWidths();
|
|
ResetChildren();
|
|
if (!OnDragUpdate)
|
|
{
|
|
Resize();
|
|
}
|
|
processDrag = false;
|
|
}
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
if (processDrag)
|
|
{
|
|
if (canvas == null)
|
|
{
|
|
throw new MissingComponentException(base.gameObject.name + " not in Canvas hierarchy.");
|
|
}
|
|
Cursor.SetCursor(CursorTexture, CursorHotSpot, Utilites.GetCursorMode());
|
|
Vector2 localPoint;
|
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position, CurrentCamera, out localPoint);
|
|
Vector2 localPoint2;
|
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position - eventData.delta, CurrentCamera, out localPoint2);
|
|
Vector2 vector = localPoint - localPoint2;
|
|
if (vector.x > 0f)
|
|
{
|
|
leftTarget.preferredWidth = Mathf.Min(leftTarget.preferredWidth + vector.x, widthLimit - rightTarget.minWidth);
|
|
rightTarget.preferredWidth = widthLimit - leftTarget.preferredWidth;
|
|
}
|
|
else
|
|
{
|
|
rightTarget.preferredWidth = Mathf.Min(rightTarget.preferredWidth - vector.x, widthLimit - leftTarget.minWidth);
|
|
leftTarget.preferredWidth = widthLimit - rightTarget.preferredWidth;
|
|
}
|
|
if (layout != null)
|
|
{
|
|
Utilites.UpdateLayout(layout);
|
|
}
|
|
if (OnDragUpdate)
|
|
{
|
|
CalculateWidths();
|
|
Resize();
|
|
}
|
|
}
|
|
}
|
|
|
|
private float GetRectWidth(RectTransform rect)
|
|
{
|
|
return rect.rect.width;
|
|
}
|
|
|
|
private void CalculateWidths()
|
|
{
|
|
widths = children.Select(GetRectWidth).ToList();
|
|
}
|
|
|
|
private void ResetChildren()
|
|
{
|
|
childrenLayouts.ForEach(ResetChildrenWidth);
|
|
}
|
|
|
|
private void ResetChildrenWidth(LayoutElement element, int index)
|
|
{
|
|
element.preferredWidth = widths[index];
|
|
}
|
|
|
|
public void Resize()
|
|
{
|
|
if (!(List == null) && widths.Count >= 2)
|
|
{
|
|
List.Start();
|
|
List.ForEachComponent(ResizeComponent);
|
|
}
|
|
}
|
|
|
|
private void Reorder()
|
|
{
|
|
if (!(List == null) && widths.Count >= 2)
|
|
{
|
|
List.Start();
|
|
List.ForEachComponent(ReorderComponent);
|
|
}
|
|
}
|
|
|
|
private void ResizeGameObject(GameObject go, int i)
|
|
{
|
|
LayoutElement component = go.GetComponent<LayoutElement>();
|
|
int index = positions.IndexOf(i);
|
|
if ((bool)component)
|
|
{
|
|
component.preferredWidth = widths[index];
|
|
}
|
|
else
|
|
{
|
|
(go.transform as RectTransform).SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, widths[index]);
|
|
}
|
|
}
|
|
|
|
private void ResizeComponent(ListViewItem component)
|
|
{
|
|
IResizableItem resizableItem = component as IResizableItem;
|
|
if (resizableItem != null)
|
|
{
|
|
resizableItem.ObjectsToResize.ForEach(ResizeGameObject);
|
|
}
|
|
}
|
|
|
|
private void ReorderComponent(ListViewItem component)
|
|
{
|
|
IResizableItem resizableItem = component as IResizableItem;
|
|
if (resizableItem == null)
|
|
{
|
|
return;
|
|
}
|
|
GameObject[] objectsToResize = resizableItem.ObjectsToResize;
|
|
int num = 0;
|
|
foreach (int position in positions)
|
|
{
|
|
objectsToResize[position].transform.SetSiblingIndex(num);
|
|
num++;
|
|
}
|
|
}
|
|
|
|
public void Reorder(int oldColumnPosition, int newColumnPosition)
|
|
{
|
|
int num = positions.IndexOf(oldColumnPosition);
|
|
int num2 = positions.IndexOf(newColumnPosition);
|
|
children[num].SetSiblingIndex(num2);
|
|
ChangePosition(childrenLayouts, num, num2);
|
|
ChangePosition(children, num, num2);
|
|
ChangePosition(positions, num, num2);
|
|
Reorder();
|
|
}
|
|
|
|
public bool CanReceiveDrop(ResizableHeaderDragCell cell, PointerEventData eventData)
|
|
{
|
|
if (!AllowReorder)
|
|
{
|
|
return false;
|
|
}
|
|
ResizableHeaderDragCell resizableHeaderDragCell = FindTarget(eventData);
|
|
return resizableHeaderDragCell != null && resizableHeaderDragCell != cell;
|
|
}
|
|
|
|
public void Drop(ResizableHeaderDragCell cell, PointerEventData eventData)
|
|
{
|
|
ResizableHeaderDragCell resizableHeaderDragCell = FindTarget(eventData);
|
|
Reorder(cell.Position, resizableHeaderDragCell.Position);
|
|
}
|
|
|
|
public void DropCanceled(ResizableHeaderDragCell cell, PointerEventData eventData)
|
|
{
|
|
}
|
|
|
|
private void ChangePosition<T>(List<T> list, int oldPosition, int newPosition)
|
|
{
|
|
T item = list[oldPosition];
|
|
list.RemoveAt(oldPosition);
|
|
list.Insert(newPosition, item);
|
|
}
|
|
|
|
private ResizableHeaderDragCell FindTarget(PointerEventData eventData)
|
|
{
|
|
raycastResults.Clear();
|
|
EventSystem.current.RaycastAll(eventData, raycastResults);
|
|
foreach (RaycastResult raycastResult in raycastResults)
|
|
{
|
|
if (raycastResult.isValid)
|
|
{
|
|
ResizableHeaderDragCell component = raycastResult.gameObject.GetComponent<ResizableHeaderDragCell>();
|
|
if (component != null && component.transform.IsChildOf(base.transform))
|
|
{
|
|
return component;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
children.Clear();
|
|
childrenLayouts.Clear();
|
|
foreach (Transform item in base.transform)
|
|
{
|
|
ResizableHeaderCell component = item.GetComponent<ResizableHeaderCell>();
|
|
if (!(component == null))
|
|
{
|
|
component.OnInitializePotentialDragEvent.RemoveListener(OnInitializePotentialDrag);
|
|
component.OnBeginDragEvent.RemoveListener(OnBeginDrag);
|
|
component.OnDragEvent.RemoveListener(OnDrag);
|
|
component.OnEndDragEvent.RemoveListener(OnEndDrag);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|