using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using UnityEngine.Events; namespace UIWidgets { /// /// Splitter type. /// public enum SplitterType { Horizontal = 0, Vertical = 1, } /// /// Splitter resize event. /// [SerializeField] public class SplitterResizeEvent : UnityEvent { } /// /// Splitter. /// [AddComponentMenu("UI/UIWidgets/Splitter")] public class Splitter : MonoBehaviour, IInitializePotentialDragHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IPointerEnterHandler, IPointerExitHandler { /// /// The type. /// public SplitterType Type = SplitterType.Vertical; /// /// Is need to update RectTransform on Resize. /// [SerializeField] public bool UpdateRectTransforms = true; /// /// Is need to update LayoutElement on Resize. /// [SerializeField] public bool UpdateLayoutElements = true; /// /// The current camera. For Screen Space - Overlay let it empty. /// [SerializeField] public Camera CurrentCamera; /// /// The cursor texture. /// [SerializeField] public Texture2D CursorTexture; /// /// The cursor hot spot. /// [SerializeField] public Vector2 CursorHotSpot = new Vector2(16, 16); /// /// The default cursor texture. /// [SerializeField] public Texture2D DefaultCursorTexture; /// /// The default cursor hot spot. /// [SerializeField] public Vector2 DefaultCursorHotSpot; /// /// OnStartResize event. /// public SplitterResizeEvent OnStartResize = new SplitterResizeEvent(); /// /// OnEndResize event. /// public SplitterResizeEvent OnEndResize = new SplitterResizeEvent(); RectTransform rectTransform; /// /// Gets the rect transform. /// /// The rect transform. public RectTransform RectTransform { get { if (rectTransform==null) { rectTransform = transform as RectTransform; } return rectTransform; } } Canvas canvas; RectTransform leftTarget; RectTransform rightTarget; LayoutElement leftTargetElement; LayoutElement LeftTargetElement { get { if (leftTargetElement==null) { leftTargetElement = leftTarget.GetComponent(); if (leftTargetElement==null) { leftTargetElement = leftTarget.gameObject.AddComponent(); } } return leftTargetElement; } } LayoutElement rightTargetElement; LayoutElement RightTargetElement { get { if (rightTargetElement==null) { rightTargetElement = rightTarget.GetComponent(); if (rightTargetElement==null) { rightTargetElement = rightTarget.gameObject.AddComponent(); } } return rightTargetElement; } } Vector2 summarySize; bool processDrag; void Start() { Init(); } /// /// Raises the initialize potential drag event. /// /// Event data. public void OnInitializePotentialDrag(PointerEventData eventData) { Init(); } /// /// Init this instance. /// public void Init() { canvas = Utilites.FindTopmostCanvas(transform).GetComponent(); } bool cursorChanged = false; protected bool IsCursorOver; /// /// Called by a BaseInputModule when an OnPointerEnter event occurs. /// /// Event data. public void OnPointerEnter(PointerEventData eventData) { IsCursorOver = true; } /// /// Called by a BaseInputModule when an OnPointerExit event occurs. /// /// Event data. public void OnPointerExit(PointerEventData eventData) { IsCursorOver = false; cursorChanged = false; Cursor.SetCursor(DefaultCursorTexture, DefaultCursorHotSpot, Utilites.GetCursorMode()); } void LateUpdate() { if (!IsCursorOver) { return ; } if (processDrag) { return ; } if (CursorTexture==null) { return ; } if (!Input.mousePresent) { return ; } Vector2 point; if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, Input.mousePosition, CurrentCamera, out point)) { return ; } var rect = RectTransform.rect; if (rect.Contains(point)) { cursorChanged = true; Cursor.SetCursor(CursorTexture, CursorHotSpot, Utilites.GetCursorMode()); } else if (cursorChanged) { cursorChanged = false; Cursor.SetCursor(DefaultCursorTexture, DefaultCursorHotSpot, Utilites.GetCursorMode()); } } /// /// Raises the begin drag event. /// /// Event data. public void OnBeginDrag(PointerEventData eventData) { Vector2 point; processDrag = false; if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.pressPosition, eventData.pressEventCamera, out point)) { return ; } var index = transform.GetSiblingIndex(); if (index==0 || transform.parent.childCount==(index+1)) { return ; } Cursor.SetCursor(CursorTexture, CursorHotSpot, Utilites.GetCursorMode()); cursorChanged = true; processDrag = true; leftTarget = transform.parent.GetChild(index - 1) as RectTransform; LeftTargetElement.preferredWidth = leftTarget.rect.width; LeftTargetElement.preferredHeight = leftTarget.rect.height; rightTarget = transform.parent.GetChild(index + 1) as RectTransform; RightTargetElement.preferredWidth = rightTarget.rect.width; RightTargetElement.preferredHeight = rightTarget.rect.height; summarySize = new Vector2(leftTarget.rect.width + rightTarget.rect.width, leftTarget.rect.height + rightTarget.rect.height); OnStartResize.Invoke(this); } /// /// Raises the end drag event. /// /// Event data. public void OnEndDrag(PointerEventData eventData) { Cursor.SetCursor(DefaultCursorTexture, DefaultCursorHotSpot, Utilites.GetCursorMode()); cursorChanged = false; processDrag = false; OnEndResize.Invoke(this); } /// /// Raises the drag event. /// /// Event data. public void OnDrag(PointerEventData eventData) { if (!processDrag) { return ; } if (canvas==null) { throw new MissingComponentException(gameObject.name + " not in Canvas hierarchy."); } Vector2 p1; RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position, CurrentCamera, out p1); Vector2 p2; RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform, eventData.position - eventData.delta, CurrentCamera, out p2); var delta = p1 - p2; if (UpdateRectTransforms) { PerformUpdateRectTransforms(delta); } if (UpdateLayoutElements) { PerformUpdateLayoutElements(delta); } } bool IsHorizontal() { return SplitterType.Horizontal==Type; } void PerformUpdateRectTransforms(Vector2 delta) { if (!IsHorizontal()) { float left_width; float right_width; if (delta.x > 0) { left_width = Mathf.Min(LeftTargetElement.preferredWidth + delta.x, summarySize.x - RightTargetElement.minWidth); right_width = summarySize.x - LeftTargetElement.preferredWidth; } else { right_width = Mathf.Min(RightTargetElement.preferredWidth - delta.x, summarySize.x - LeftTargetElement.minWidth); left_width = summarySize.x - RightTargetElement.preferredWidth; } leftTarget.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, left_width); rightTarget.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, right_width); } else { float left_height; float right_height; delta.y *= -1; if (delta.y > 0) { left_height = Mathf.Min(LeftTargetElement.preferredHeight + delta.y, summarySize.y - RightTargetElement.minHeight); right_height = summarySize.y - LeftTargetElement.preferredHeight; } else { right_height = Mathf.Min(RightTargetElement.preferredHeight - delta.y, summarySize.y - LeftTargetElement.minHeight); left_height = summarySize.y - RightTargetElement.preferredHeight; } leftTarget.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, left_height); rightTarget.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, right_height); } } void PerformUpdateLayoutElements(Vector2 delta) { if (!IsHorizontal()) { if (delta.x > 0) { LeftTargetElement.preferredWidth = Mathf.Min(LeftTargetElement.preferredWidth + delta.x, summarySize.x - RightTargetElement.minWidth); RightTargetElement.preferredWidth = summarySize.x - LeftTargetElement.preferredWidth; } else { RightTargetElement.preferredWidth = Mathf.Min(RightTargetElement.preferredWidth - delta.x, summarySize.x - LeftTargetElement.minWidth); LeftTargetElement.preferredWidth = summarySize.x - RightTargetElement.preferredWidth; } } else { delta.y *= -1; if (delta.y > 0) { LeftTargetElement.preferredHeight = Mathf.Min(LeftTargetElement.preferredHeight + delta.y, summarySize.y - RightTargetElement.minHeight); RightTargetElement.preferredHeight = summarySize.y - LeftTargetElement.preferredHeight; } else { RightTargetElement.preferredHeight = Mathf.Min(RightTargetElement.preferredHeight - delta.y, summarySize.y - LeftTargetElement.minHeight); LeftTargetElement.preferredHeight = summarySize.y - RightTargetElement.preferredHeight; } } } } }