using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; namespace EasyLayout { [RequireComponent(typeof(RectTransform))] [ExecuteInEditMode] public class EasyLayout : LayoutGroup { [SerializeField] public Anchors GroupPosition; [SerializeField] public Stackings Stacking; [SerializeField] public LayoutTypes LayoutType; [SerializeField] public HorizontalAligns RowAlign; [SerializeField] public InnerAligns InnerAlign; [SerializeField] public Anchors CellAlign; [SerializeField] public Vector2 Spacing = new Vector2(5f, 5f); [SerializeField] public bool Symmetric = true; [SerializeField] public Vector2 Margin = new Vector2(5f, 5f); [SerializeField] public Padding PaddingInner = default(Padding); [SerializeField] public float MarginTop = 5f; [SerializeField] public float MarginBottom = 5f; [SerializeField] public float MarginLeft = 5f; [SerializeField] public float MarginRight = 5f; [SerializeField] public bool RightToLeft; [SerializeField] public bool TopToBottom = true; [SerializeField] public bool SkipInactive = true; public Func, IEnumerable> Filter; public ChildrenSize ChildrenWidth; public ChildrenSize ChildrenHeight; [SerializeField] [Obsolete("Use ChildrenWidth with ChildrenSize.SetPreferred instead.")] public bool ControlWidth; [Obsolete("Use ChildrenHeight with ChildrenSize.SetPreferred instead.")] [SerializeField] public bool ControlHeight; [SerializeField] [Obsolete("Use ChildrenWidth with ChildrenSize.SetMaxFromPreferred instead.")] public bool MaxWidth; [Obsolete("Use ChildrenHeight with ChildrenSize.SetMaxFromPreferred instead.")] [SerializeField] public bool MaxHeight; private Vector2 _blockSize; private Vector2 _uiSize; private static readonly Dictionary groupPositions = new Dictionary { { Anchors.LowerLeft, new Vector2(0f, 0f) }, { Anchors.LowerCenter, new Vector2(0.5f, 0f) }, { Anchors.LowerRight, new Vector2(1f, 0f) }, { Anchors.MiddleLeft, new Vector2(0f, 0.5f) }, { Anchors.MiddleCenter, new Vector2(0.5f, 0.5f) }, { Anchors.MiddleRight, new Vector2(1f, 0.5f) }, { Anchors.UpperLeft, new Vector2(0f, 1f) }, { Anchors.UpperCenter, new Vector2(0.5f, 1f) }, { Anchors.UpperRight, new Vector2(1f, 1f) } }; private static readonly Dictionary rowAligns = new Dictionary { { HorizontalAligns.Left, 0f }, { HorizontalAligns.Center, 0.5f }, { HorizontalAligns.Right, 1f } }; private static readonly Dictionary innerAligns = new Dictionary { { InnerAligns.Top, 0f }, { InnerAligns.Middle, 0.5f }, { InnerAligns.Bottom, 1f } }; private float max_width = -1f; private float max_height = -1f; private DrivenRectTransformTracker propertiesTracker; [SerializeField] private int version; public Vector2 BlockSize { get { return _blockSize; } protected set { _blockSize = value; } } public Vector2 UISize { get { return _uiSize; } protected set { _uiSize = value; } } public override float minHeight { get { return BlockSize[1]; } } public override float minWidth { get { return BlockSize[0]; } } public override float preferredHeight { get { return BlockSize[1]; } } public override float preferredWidth { get { return BlockSize[0]; } } protected override void OnDisable() { propertiesTracker.Clear(); base.OnDisable(); } public void OnRectTransformRemoved() { SetDirty(); } public override void SetLayoutHorizontal() { RepositionUIElements(); } public override void SetLayoutVertical() { } public override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal(); CalculateLayoutSize(); } public override void CalculateLayoutInputVertical() { } public float GetLength(RectTransform ui, bool scaled = true) { if (scaled) { return (Stacking != Stackings.Horizontal) ? ScaledHeight(ui) : ScaledWidth(ui); } return (Stacking != Stackings.Horizontal) ? ui.rect.height : ui.rect.width; } private float GetRowWidth(List row) { return row.Select(ScaledWidth).Sum() + Spacing.x * (float)(row.Count - 1); } private float GetRowHeight(List row) { return row.Select(ScaledHeight).Max() + Spacing.y; } private Vector2 CalculateGroupSize(List> group) { float num; if (LayoutType == LayoutTypes.Compact) { num = group.Select(GetRowWidth).Max(); } else { float[] maxColumnsWidths = GetMaxColumnsWidths(group); num = maxColumnsWidths.Sum() + (float)maxColumnsWidths.Length * Spacing.x - Spacing.x; } float num2 = group.Select(GetRowHeight).Sum() - Spacing.y; num += PaddingInner.Left + PaddingInner.Right; num2 += PaddingInner.Top + PaddingInner.Bottom; return new Vector2(num, num2); } public void NeedUpdateLayout() { UpdateLayout(); } private void UpdateBlockSize() { if (Symmetric) { BlockSize = new Vector2(UISize.x + Margin.x * 2f, UISize.y + Margin.y * 2f); } else { BlockSize = new Vector2(UISize.x + MarginLeft + MarginRight, UISize.y + MarginLeft + MarginRight); } } public void CalculateLayoutSize() { List> list = GroupUIElements(); if (list.Count == 0) { UISize = new Vector2(0f, 0f); UpdateBlockSize(); } else { UISize = CalculateGroupSize(list); UpdateBlockSize(); } } public void RepositionUIElements() { List> list = GroupUIElements(); if (list.Count == 0) { UISize = new Vector2(0f, 0f); UpdateBlockSize(); return; } UISize = CalculateGroupSize(list); UpdateBlockSize(); Vector2 vector = groupPositions[GroupPosition]; Vector2 startPosition = new Vector2(base.rectTransform.rect.width * (vector.x - base.rectTransform.pivot.x), base.rectTransform.rect.height * (vector.y - base.rectTransform.pivot.y)); startPosition.x -= vector.x * UISize.x; startPosition.y += (1f - vector.y) * UISize.y; startPosition.x += GetMarginLeft() * ((1f - vector.x) * 2f - 1f); startPosition.y += GetMarginTop() * ((1f - vector.y) * 2f - 1f); startPosition.x += PaddingInner.Left; startPosition.y -= PaddingInner.Top; SetPositions(list, startPosition, UISize); } public void UpdateLayout() { CalculateLayoutInputHorizontal(); RepositionUIElements(); } private Vector2 GetUIPosition(RectTransform ui, Vector2 position, Vector2 align) { float num = ScaledWidth(ui) * ui.pivot.x; float num2 = ScaledHeight(ui) * ui.pivot.y; float x = position.x + num + align.x; float y = position.y - ScaledHeight(ui) + num2 - align.y; return new Vector2(x, y); } private List GetRowsWidths(List> group) { List list = new List(); foreach (int item in Enumerable.Range(0, group.Count)) { float num = group[item].Convert(ScaledWidth).Sum(); list.Add(num + (float)(group[item].Count - 1) * Spacing.x); } return list; } private float GetMaxColumnWidth(List column) { return column.Convert(ScaledWidth).Max(); } private float[] GetMaxColumnsWidths(List> group) { return Transpose(group).Select(GetMaxColumnWidth).ToArray(); } private List GetColumnsHeights(List> group) { List list = new List(); foreach (int item in Enumerable.Range(0, group.Count)) { float num = group[item].Convert(ScaledHeight).Sum(); list.Add(num + (float)(group[item].Count - 1) * Spacing.y); } return list; } private float GetMaxRowHeight(List row) { return row.Select(ScaledHeight).Max(); } private float[] GetMaxRowsHeights(List> group) { return Transpose(group).Convert(GetMaxRowHeight).ToArray(); } private Vector2 GetMaxCellSize(List> group) { List source = group.Convert(GetMaxCellSize); return new Vector2(((IEnumerable)source).Max((Func)GetWidth), ((IEnumerable)source).Max((Func)GetHeight)); } private float GetWidth(Vector2 size) { return size.x; } private float GetHeight(Vector2 size) { return size.y; } private Vector2 GetMaxCellSize(List row) { return new Vector2(((IEnumerable)row).Max((Func)ScaledWidth), ((IEnumerable)row).Max((Func)ScaledHeight)); } private Vector2 GetAlignByWidth(RectTransform ui, float maxWidth, Vector2 cellMaxSize, float emptyWidth) { if (LayoutType == LayoutTypes.Compact) { return new Vector2(emptyWidth * rowAligns[RowAlign], (cellMaxSize.y - ScaledHeight(ui)) * innerAligns[InnerAlign]); } Vector2 vector = groupPositions[CellAlign]; return new Vector2((maxWidth - ScaledWidth(ui)) * vector.x, (cellMaxSize.y - ScaledHeight(ui)) * (1f - vector.y)); } private Vector2 GetAlignByHeight(RectTransform ui, float maxHeight, Vector2 cellMaxSize, float emptyHeight) { if (LayoutType == LayoutTypes.Compact) { return new Vector2((cellMaxSize.x - ScaledWidth(ui)) * innerAligns[InnerAlign], emptyHeight * rowAligns[RowAlign]); } Vector2 vector = groupPositions[CellAlign]; return new Vector2((cellMaxSize.x - ScaledWidth(ui)) * (1f - vector.x), (maxHeight - ScaledHeight(ui)) * vector.y); } private void SetPositions(List> group, Vector2 startPosition, Vector2 groupSize) { Vector2 position = startPosition; if (Stacking == Stackings.Horizontal) { List rowsWidths = GetRowsWidths(group); float[] maxColumnsWidths = GetMaxColumnsWidths(group); Vector2 vector = new Vector2(0f, 0f); int num = 0; { foreach (List item in group) { Vector2 maxCellSize = GetMaxCellSize(item); int num2 = 0; foreach (RectTransform item2 in item) { vector = GetAlignByWidth(item2, maxColumnsWidths[num2], maxCellSize, groupSize.x - rowsWidths[num]); Vector2 uIPosition = GetUIPosition(item2, position, vector); if (item2.localPosition.x != uIPosition.x || item2.localPosition.y != uIPosition.y) { item2.localPosition = uIPosition; } position.x += ((LayoutType != LayoutTypes.Compact) ? maxColumnsWidths[num2] : ScaledWidth(item2)) + Spacing.x; num2++; } position.x = startPosition.x; position.y -= maxCellSize.y + Spacing.y; num++; } return; } } group = Transpose(group); List columnsHeights = GetColumnsHeights(group); float[] maxRowsHeights = GetMaxRowsHeights(group); Vector2 vector2 = new Vector2(0f, 0f); int num3 = 0; foreach (List item3 in group) { Vector2 maxCellSize2 = GetMaxCellSize(item3); int num4 = 0; foreach (RectTransform item4 in item3) { vector2 = GetAlignByHeight(item4, maxRowsHeights[num4], maxCellSize2, groupSize.y - columnsHeights[num3]); Vector2 uIPosition2 = GetUIPosition(item4, position, vector2); if (item4.localPosition.x != uIPosition2.x || item4.localPosition.y != uIPosition2.y) { item4.localPosition = uIPosition2; } position.y -= ((LayoutType != LayoutTypes.Compact) ? maxRowsHeights[num4] : ScaledHeight(item4)) + Spacing.y; num4++; } position.y = startPosition.y; position.x += maxCellSize2.x + Spacing.x; num3++; } } private void ResizeElements(List elements) { propertiesTracker.Clear(); if ((ChildrenWidth != ChildrenSize.DoNothing || ChildrenHeight != ChildrenSize.DoNothing) && elements != null && elements.Count != 0) { max_width = ((ChildrenWidth != ChildrenSize.SetMaxFromPreferred) ? (-1f) : elements.Select(GetPreferredWidth).Max()); max_height = ((ChildrenHeight != ChildrenSize.SetMaxFromPreferred) ? (-1f) : elements.Select(GetPreferredHeight).Max()); elements.ForEach(ResizeChild); } } public static float GetPreferredWidth(RectTransform rect) { if (rect == null) { return 1f; } if (rect.gameObject.activeInHierarchy) { return Mathf.Max(1f, LayoutUtility.GetPreferredWidth(rect)); } float num = 1f; ILayoutElement[] components = rect.GetComponents(); int num2 = components.Max((ILayoutElement x) => x.layoutPriority); ILayoutElement[] array = components; foreach (ILayoutElement layoutElement in array) { if (layoutElement.layoutPriority == num2) { num = Mathf.Max(num, Mathf.Max(layoutElement.preferredWidth, layoutElement.minWidth)); } } return num; } public static float GetPreferredHeight(RectTransform rect) { if (rect == null) { return 1f; } if (rect.gameObject.activeInHierarchy) { return Mathf.Max(1f, LayoutUtility.GetPreferredHeight(rect)); } float num = 1f; ILayoutElement[] components = rect.GetComponents(); int num2 = components.Max((ILayoutElement x) => x.layoutPriority); ILayoutElement[] array = components; foreach (ILayoutElement layoutElement in array) { if (layoutElement.layoutPriority == num2) { num = Mathf.Max(num, Mathf.Max(layoutElement.preferredHeight, layoutElement.minHeight)); } } return num; } public static float GetFlexibleWidth(RectTransform rect) { if (rect == null) { return 1f; } if (rect.gameObject.activeInHierarchy) { return Mathf.Max(1f, LayoutUtility.GetFlexibleWidth(rect)); } float num = 1f; ILayoutElement[] components = rect.GetComponents(); int num2 = components.Max((ILayoutElement x) => x.layoutPriority); ILayoutElement[] array = components; foreach (ILayoutElement layoutElement in array) { if (layoutElement.layoutPriority == num2) { num = Mathf.Max(num, layoutElement.flexibleWidth); } } return num; } public static float GetFlexibleHeight(RectTransform rect) { if (rect == null) { return 1f; } if (rect.gameObject.activeInHierarchy) { return Mathf.Max(1f, LayoutUtility.GetFlexibleHeight(rect)); } float num = 1f; ILayoutElement[] components = rect.GetComponents(); int num2 = components.Max((ILayoutElement x) => x.layoutPriority); ILayoutElement[] array = components; foreach (ILayoutElement layoutElement in array) { if (layoutElement.layoutPriority == num2) { num = Mathf.Max(num, layoutElement.flexibleHeight); } } return num; } private void ResizeChild(RectTransform child) { DrivenTransformProperties drivenTransformProperties = DrivenTransformProperties.None; if (ChildrenWidth != ChildrenSize.DoNothing) { drivenTransformProperties |= DrivenTransformProperties.SizeDeltaX; float size = ((max_width == -1f) ? GetPreferredWidth(child) : max_width); child.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size); } if (ChildrenHeight != ChildrenSize.DoNothing) { drivenTransformProperties |= DrivenTransformProperties.SizeDeltaY; float size2 = ((max_height == -1f) ? GetPreferredHeight(child) : max_height); child.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size2); } propertiesTracker.Add(this, child, drivenTransformProperties); } private bool IsIgnoreLayout(Transform rect) { ILayoutIgnorer component = rect.GetComponent(); return component != null && component.ignoreLayout; } private List GetUIElements() { List list = base.rectChildren; if (!SkipInactive) { list = new List(); foreach (Transform item in base.transform) { if (!IsIgnoreLayout(item)) { list.Add(item as RectTransform); } } } if (Filter != null) { IEnumerable source = Filter(list.Convert(GetGameObject)); List list2 = source.Select(GetRectTransform).ToList(); ResizeElements(list2); return list2; } ResizeElements(list); return list; } private GameObject GetGameObject(RectTransform element) { return element.gameObject; } private RectTransform GetRectTransform(GameObject go) { return go.transform as RectTransform; } public float GetMarginTop() { return (!Symmetric) ? MarginTop : Margin.y; } public float GetMarginBottom() { return (!Symmetric) ? MarginBottom : Margin.y; } public float GetMarginLeft() { return (!Symmetric) ? MarginLeft : Margin.x; } public float GetMarginRight() { return (!Symmetric) ? MarginRight : Margin.y; } private void ReverseList(List list) { list.Reverse(); } private List> GroupUIElements() { float length = GetLength(base.rectTransform, false); length -= ((Stacking != Stackings.Horizontal) ? (GetMarginTop() + GetMarginBottom()) : (GetMarginLeft() + GetMarginRight())); List uIElements = GetUIElements(); List> list = ((LayoutType != LayoutTypes.Compact) ? EasyLayoutGrid.Group(uIElements, length, this) : EasyLayoutCompact.Group(uIElements, length, this)); if (Stacking == Stackings.Vertical) { list = Transpose(list); } if (!TopToBottom) { list.Reverse(); } if (RightToLeft) { list.ForEach(ReverseList); } float width = base.rectTransform.rect.width - (GetMarginLeft() + GetMarginRight()); float height = base.rectTransform.rect.height - (GetMarginTop() + GetMarginBottom()); if (LayoutType == LayoutTypes.Grid) { if (ChildrenWidth == ChildrenSize.FitContainer) { ResizeColumnWidthToFit(width, list); } if (ChildrenHeight == ChildrenSize.FitContainer) { ResizeRowHeightToFit(height, list); } } else if (Stacking == Stackings.Horizontal) { if (ChildrenWidth == ChildrenSize.FitContainer) { ResizeWidthToFit(width, list); } if (ChildrenHeight == ChildrenSize.FitContainer) { ResizeRowHeightToFit(height, list); } } else { if (ChildrenHeight == ChildrenSize.FitContainer) { ResizeHeightToFit(height, list); } if (ChildrenWidth == ChildrenSize.FitContainer) { ResizeColumnWidthToFit(width, list); } } return list; } private float GetRectWidth(RectTransform rect) { return rect.rect.width; } private float GetRectHeight(RectTransform rect) { return rect.rect.height; } private void ResizeWidthToFit(float width, List> group) { foreach (List item in group) { float num = width - item.SumFloat(GetRectWidth) - (float)(item.Count - 1) * Spacing.x; if (num <= 0f) { continue; } float num2 = num / item.SumFloat(GetFlexibleWidth); foreach (RectTransform item2 in item) { float num3 = GetFlexibleWidth(item2); item2.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, item2.rect.width + num2 * num3); } } } private float GetMaxPreferredWidth(List row) { return ((IEnumerable)row).Max((Func)GetPreferredWidth); } private float GetMaxFlexibleWidth(List row) { return ((IEnumerable)row).Max((Func)GetFlexibleWidth); } private void ResizeColumnWidthToFit(float width, List> group) { List> list = Transpose(group); List list2 = list.Convert(GetMaxPreferredWidth); List list3 = list.Convert(GetMaxFlexibleWidth); float num = width - list2.Sum() - (float)(list.Count - 1) * Spacing.x - PaddingInner.Left - PaddingInner.Right; if (num <= 0f) { return; } float num2 = num / list3.Sum(); int num3 = 0; foreach (List item in list) { foreach (RectTransform item2 in item) { item2.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, list2[num3] + num2 * list3[num3]); } num3++; } } private void ResizeHeightToFit(float height, List> group) { foreach (List item in Transpose(group)) { float num = height - item.SumFloat(GetRectHeight) - (float)(item.Count - 1) * Spacing.y; if (num <= 0f) { continue; } float num2 = num / item.SumFloat(GetFlexibleHeight); foreach (RectTransform item2 in item) { float num3 = Mathf.Max(1f, GetFlexibleHeight(item2)); item2.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, item2.rect.height + num2 * num3); } } } private float GetMaxPreferredHeight(List column) { return ((IEnumerable)column).Max((Func)GetPreferredWidth); } private float GetMaxFlexibleHeight(List column) { return ((IEnumerable)column).Max((Func)GetFlexibleHeight); } private void ResizeRowHeightToFit(float height, List> group) { List list = group.Convert(GetMaxPreferredHeight); List list2 = group.Convert(GetMaxFlexibleHeight); float num = height - list.Sum() - (float)(group.Count - 1) * Spacing.y - PaddingInner.Top - PaddingInner.Bottom; if (num <= 0f) { return; } float num2 = num / list2.Sum(); int num3 = 0; foreach (List item in group) { foreach (RectTransform item2 in item) { item2.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, list[num3] + num2 * list2[num3]); } num3++; } } public static List> Transpose(List> group) { List> list = new List>(); int num = 0; foreach (List item in group) { int num2 = 0; foreach (T item2 in item) { if (list.Count <= num2) { list.Add(new List()); } list[num2].Add(item2); num2++; } num++; } return list; } private static void Log(IEnumerable values) { Debug.Log("[" + string.Join("; ", values.Select((float x) => x.ToString()).ToArray()) + "]"); } private float ScaledWidth(RectTransform ui) { return ui.rect.width * ui.localScale.x; } private float ScaledHeight(RectTransform ui) { return ui.rect.height * ui.localScale.y; } protected override void Awake() { base.Awake(); Upgrade(); } public virtual void Upgrade() { if (version == 0) { if (ControlWidth) { ChildrenWidth = ((!MaxWidth) ? ChildrenSize.SetPreferred : ChildrenSize.SetMaxFromPreferred); } if (ControlHeight) { ChildrenHeight = ((!MaxHeight) ? ChildrenSize.SetPreferred : ChildrenSize.SetMaxFromPreferred); } } version = 1; } } }