using UnityEngine; using UnityEngine.UI; namespace Cryville.Common.Unity.UI { /// /// A that docks its first child element to one side. /// public abstract class DockLayoutGroup : LayoutGroup { /// /// The dock side. /// public enum Side { /// /// Top. /// Top = 0, /// /// Right. /// Right = 1, /// /// Bottom. /// Bottom = 2, /// /// Left. /// Left = 3, } [SerializeField] [Tooltip("The docking side of the first child element.")] private Side m_side; /// /// The docking side of the first child element. /// public Side DockSide { get { return m_side; } set { base.SetProperty(ref m_side, value); } } [SerializeField] [Tooltip("The slide index. The children slide along the cross axis.")] private float m_slideIndex; /// /// The slide index. The children slide along the axis. /// public float SlideIndex { get { return m_slideIndex; } set { base.SetProperty(ref m_slideIndex, value); } } /// public sealed override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal(); } /// public sealed override void CalculateLayoutInputVertical() { } /// public sealed override void SetLayoutHorizontal() { SetChildrenAlongAxis(0); } /// public sealed override void SetLayoutVertical() { SetChildrenAlongAxis(1); } private float GetSlidePosition(float groupHeight, float dockHeight) { bool d = Mathf.FloorToInt(m_slideIndex - Mathf.Floor(m_slideIndex / 2) * 2) == 0; int l = Mathf.FloorToInt(m_slideIndex / 2); float p = m_slideIndex - Mathf.Floor(m_slideIndex); if (d) return l * groupHeight + p * dockHeight; else return l * groupHeight + dockHeight + p * (groupHeight - dockHeight); } private void SetChildrenAlongAxis(int axis) { int isHorizontal = (int)m_side & 1; bool isReversed = m_side == Side.Right || m_side == Side.Bottom; var rect = rectTransform.rect; if ((isHorizontal ^ axis) == 1) { float p0 = isHorizontal == 1 ? m_Padding.left : m_Padding.top; float p1 = isHorizontal == 1 ? m_Padding.right : m_Padding.bottom; var gs = rect.size - new Vector2(m_Padding.horizontal, m_Padding.vertical); if (isHorizontal == 0) gs = new Vector2(gs.y, gs.x); float s1 = GetDockElementSize(gs); float s0 = GetSlidePosition(gs.x, s1); float a1 = (isHorizontal == 0 ? rect.height : rect.width) - p0 - p1; for (int i = 0; i < base.rectChildren.Count; i++) { var c = base.rectChildren[i]; bool d = i % 2 == 0; int l = i / 2; if (isReversed) base.SetChildAlongAxis(c, axis, (d ? a1 - s1 + p0 : p0) - a1 * l + s0, d ? s1 : a1 - s1); else base.SetChildAlongAxis(c, axis, (d ? p0 : s1 + p0) - s0 + a1 * l, d ? s1 : a1 - s1); } } else { float p0 = isHorizontal == 0 ? m_Padding.left : m_Padding.top; float p1 = isHorizontal == 0 ? m_Padding.right : m_Padding.bottom; var height = (isHorizontal == 1 ? rect.height : rect.width) - p0 - p1; for (int i = 0; i < base.rectChildren.Count; i++) { base.SetChildAlongAxis(base.rectChildren[i], axis, p0, height); } } } /// /// Gets the length of the first child element along the axis. /// /// The size of the layout group. /// protected abstract float GetDockElementSize(Vector2 groupSize); } }