diff --git a/Scripts/Layout/TableLayoutGroup.cs b/Scripts/Layout/TableLayoutGroup.cs index 6c44751..87a92ae 100644 --- a/Scripts/Layout/TableLayoutGroup.cs +++ b/Scripts/Layout/TableLayoutGroup.cs @@ -1,290 +1,291 @@ -/// Credit RahulOfTheRamanEffect -/// Sourced from - https://forum.unity3d.com/members/rahuloftheramaneffect.773241/ - -namespace UnityEngine.UI.Extensions -{ - /// - /// Arranges child objects into a non-uniform grid, with fixed column widths and flexible row heights - /// - public class TableLayoutGroup : LayoutGroup - { - public enum Corner - { - UpperLeft = 0, - UpperRight = 1, - LowerLeft = 2, - LowerRight = 3 - } - - [SerializeField] - protected Corner startCorner = Corner.UpperLeft; - /// - /// The corner starting from which the cells should be arranged - /// - public Corner StartCorner - { - get { return startCorner; } - set - { - SetProperty(ref startCorner, value); - } - } - - [SerializeField] - protected float[] columnWidths = new float[1] { 96f }; - /// - /// The widths of all the columns in the table - /// - public float[] ColumnWidths - { - get { return columnWidths; } - set - { - SetProperty(ref columnWidths, value); - } - } - - [SerializeField] - protected float minimumRowHeight = 32f; - /// - /// The minimum height for any row in the table - /// - public float MinimumRowHeight - { - get { return minimumRowHeight; } - set - { - SetProperty(ref minimumRowHeight, value); - } - } - - [SerializeField] - protected bool flexibleRowHeight = true; - /// - /// Expand rows to fit the cell with the highest preferred height? - /// - public bool FlexibleRowHeight - { - get { return flexibleRowHeight; } - set - { - SetProperty(ref flexibleRowHeight, value); - } - } - - [SerializeField] - protected float columnSpacing = 0f; - /// - /// The horizontal spacing between each cell in the table - /// - public float ColumnSpacing - { - get { return columnSpacing; } - set - { - SetProperty(ref columnSpacing, value); - } - } - - [SerializeField] - protected float rowSpacing = 0; - /// - /// The vertical spacing between each row in the table - /// - public float RowSpacing - { - get { return rowSpacing; } - set - { - SetProperty(ref rowSpacing, value); - } - } - - // Temporarily stores data generated during the execution CalculateLayoutInputVertical for use in SetLayoutVertical - private float[] preferredRowHeights; - - public override void CalculateLayoutInputHorizontal() - { - base.CalculateLayoutInputHorizontal(); - - float horizontalSize = padding.horizontal; - - // We calculate the actual cell count for cases where the number of children is lesser than the number of columns - int actualCellCount = Mathf.Min(rectChildren.Count, columnWidths.Length); - - for (int i = 0; i < actualCellCount; i++) - { - horizontalSize += columnWidths[i]; - horizontalSize += columnSpacing; - } - - horizontalSize -= columnSpacing; - - SetLayoutInputForAxis(horizontalSize, horizontalSize, 0, 0); - } - - public override void CalculateLayoutInputVertical() - { - int columnCount = columnWidths.Length; - int rowCount = Mathf.CeilToInt(rectChildren.Count / (float)columnCount); - - preferredRowHeights = new float[rowCount]; - - float totalMinHeight = padding.vertical; - float totalPreferredHeight = padding.vertical; - - if (rowCount > 1) - { - float heightFromSpacing = ((rowCount - 1) * rowSpacing); - totalMinHeight += heightFromSpacing; - totalPreferredHeight += heightFromSpacing; - } - - if (flexibleRowHeight) - { - // If flexibleRowHeight is enabled, find the max value for minimum and preferred heights in each row - - float maxMinimumHeightInRow = 0; - float maxPreferredHeightInRow = 0; - - for (int i = 0; i < rectChildren.Count; i++) - { - int currentRowIndex = i / columnCount; - int currentColumnIndex = i % columnCount; - - // If it's the first cell in the row, reset heights for the row - if (currentColumnIndex == 0) - { - maxMinimumHeightInRow = minimumRowHeight; - maxPreferredHeightInRow = minimumRowHeight; - } - - maxPreferredHeightInRow = Mathf.Max(LayoutUtility.GetPreferredHeight(rectChildren[i]), maxPreferredHeightInRow); - maxMinimumHeightInRow = Mathf.Max(LayoutUtility.GetMinHeight(rectChildren[i]), maxMinimumHeightInRow); - - // If it's the last cell in the row, or if it's the last cell and the row is incomplete, set calculated heights - if (currentColumnIndex == columnCount - 1 || (i == rectChildren.Count - 1 && currentRowIndex == rowCount - 1)) - { - totalMinHeight += maxMinimumHeightInRow; - totalPreferredHeight += maxPreferredHeightInRow; - - // Add calculated row height to a commonly accessible array for reuse in SetLayoutVertical() - preferredRowHeights[currentRowIndex] = maxPreferredHeightInRow; - } - } - } - else - { - // If flexibleRowHeight is disabled, then use the minimumRowHeight to calculate vertical layout information - for (int i = 0; i < rowCount; i++) - preferredRowHeights[i] = minimumRowHeight; - - totalMinHeight += rowCount * minimumRowHeight; - totalPreferredHeight = totalMinHeight; - } - - totalPreferredHeight = Mathf.Max(totalMinHeight, totalPreferredHeight); - SetLayoutInputForAxis(totalMinHeight, totalPreferredHeight, 1, 1); - } - - public override void SetLayoutHorizontal() - { - // If no column width is defined, then assign a reasonable default - if (columnWidths.Length == 0) - columnWidths = new float[1] { 0f }; - - int columnCount = columnWidths.Length; - int cornerX = (int)startCorner % 2; - - float startOffset = 0; - float requiredSizeWithoutPadding = 0; - - // We calculate the actual cell count for cases where the number of children is lesser than the number of columns - int actualCellCount = Mathf.Min(rectChildren.Count, columnWidths.Length); - - for (int i = 0; i < actualCellCount; i++) - { - requiredSizeWithoutPadding += columnWidths[i]; - requiredSizeWithoutPadding += columnSpacing; - } - - requiredSizeWithoutPadding -= columnSpacing; - - startOffset = GetStartOffset(0, requiredSizeWithoutPadding); - - if (cornerX == 1) - startOffset += requiredSizeWithoutPadding; - - float positionX = startOffset; - - for (int i = 0; i < rectChildren.Count; i++) - { - int currentColumnIndex = i % columnCount; - - // If it's the first cell in the row, reset positionX - if (currentColumnIndex == 0) - positionX = startOffset; - - if (cornerX == 1) - positionX -= columnWidths[currentColumnIndex]; - - SetChildAlongAxis(rectChildren[i], 0, positionX, columnWidths[currentColumnIndex]); - - if (cornerX == 1) - positionX -= columnSpacing; - else - positionX += columnWidths[currentColumnIndex] + columnSpacing; - } - } - - public override void SetLayoutVertical() - { - int columnCount = columnWidths.Length; - int rowCount = preferredRowHeights.Length; - - int cornerY = (int)startCorner / 2; - - float startOffset = 0; - float requiredSizeWithoutPadding = 0; - - for (int i = 0; i < rowCount; i++) - { - requiredSizeWithoutPadding += preferredRowHeights[i]; - requiredSizeWithoutPadding += rowSpacing; - } - - requiredSizeWithoutPadding -= rowSpacing; - - startOffset = GetStartOffset(1, requiredSizeWithoutPadding); - - if (cornerY == 1) - startOffset += requiredSizeWithoutPadding; - - float positionY = startOffset; - - for (int i = 0; i < rectChildren.Count; i++) - { - int currentRowIndex = i / columnCount; - int currentColumnIndex = i % columnCount; - - // If it's the first cell in the row and start corner is one of the bottom corners, then modify positionY appropriately - if (currentColumnIndex == 0 && cornerY == 1) - positionY -= preferredRowHeights[currentRowIndex]; - - SetChildAlongAxis(rectChildren[i], 1, positionY, preferredRowHeights[currentRowIndex]); - - // If it's the first last cell in the row, then modify positionY appropriately - if (currentColumnIndex == columnCount - 1) - { - if (cornerY == 1) - positionY -= rowSpacing; - else - positionY += preferredRowHeights[currentRowIndex] + rowSpacing; - } - } - - // Set preferredRowHeights to null to free memory - preferredRowHeights = null; - } - } +/// Credit RahulOfTheRamanEffect +/// Sourced from - https://forum.unity3d.com/members/rahuloftheramaneffect.773241/ + +namespace UnityEngine.UI.Extensions +{ + /// + /// Arranges child objects into a non-uniform grid, with fixed column widths and flexible row heights + /// + [AddComponentMenu("Layout/Extensions/Table Layout Group")] + public class TableLayoutGroup : LayoutGroup + { + public enum Corner + { + UpperLeft = 0, + UpperRight = 1, + LowerLeft = 2, + LowerRight = 3 + } + + [SerializeField] + protected Corner startCorner = Corner.UpperLeft; + /// + /// The corner starting from which the cells should be arranged + /// + public Corner StartCorner + { + get { return startCorner; } + set + { + SetProperty(ref startCorner, value); + } + } + + [SerializeField] + protected float[] columnWidths = new float[1] { 96f }; + /// + /// The widths of all the columns in the table + /// + public float[] ColumnWidths + { + get { return columnWidths; } + set + { + SetProperty(ref columnWidths, value); + } + } + + [SerializeField] + protected float minimumRowHeight = 32f; + /// + /// The minimum height for any row in the table + /// + public float MinimumRowHeight + { + get { return minimumRowHeight; } + set + { + SetProperty(ref minimumRowHeight, value); + } + } + + [SerializeField] + protected bool flexibleRowHeight = true; + /// + /// Expand rows to fit the cell with the highest preferred height? + /// + public bool FlexibleRowHeight + { + get { return flexibleRowHeight; } + set + { + SetProperty(ref flexibleRowHeight, value); + } + } + + [SerializeField] + protected float columnSpacing = 0f; + /// + /// The horizontal spacing between each cell in the table + /// + public float ColumnSpacing + { + get { return columnSpacing; } + set + { + SetProperty(ref columnSpacing, value); + } + } + + [SerializeField] + protected float rowSpacing = 0; + /// + /// The vertical spacing between each row in the table + /// + public float RowSpacing + { + get { return rowSpacing; } + set + { + SetProperty(ref rowSpacing, value); + } + } + + // Temporarily stores data generated during the execution CalculateLayoutInputVertical for use in SetLayoutVertical + private float[] preferredRowHeights; + + public override void CalculateLayoutInputHorizontal() + { + base.CalculateLayoutInputHorizontal(); + + float horizontalSize = padding.horizontal; + + // We calculate the actual cell count for cases where the number of children is lesser than the number of columns + int actualCellCount = Mathf.Min(rectChildren.Count, columnWidths.Length); + + for (int i = 0; i < actualCellCount; i++) + { + horizontalSize += columnWidths[i]; + horizontalSize += columnSpacing; + } + + horizontalSize -= columnSpacing; + + SetLayoutInputForAxis(horizontalSize, horizontalSize, 0, 0); + } + + public override void CalculateLayoutInputVertical() + { + int columnCount = columnWidths.Length; + int rowCount = Mathf.CeilToInt(rectChildren.Count / (float)columnCount); + + preferredRowHeights = new float[rowCount]; + + float totalMinHeight = padding.vertical; + float totalPreferredHeight = padding.vertical; + + if (rowCount > 1) + { + float heightFromSpacing = ((rowCount - 1) * rowSpacing); + totalMinHeight += heightFromSpacing; + totalPreferredHeight += heightFromSpacing; + } + + if (flexibleRowHeight) + { + // If flexibleRowHeight is enabled, find the max value for minimum and preferred heights in each row + + float maxMinimumHeightInRow = 0; + float maxPreferredHeightInRow = 0; + + for (int i = 0; i < rectChildren.Count; i++) + { + int currentRowIndex = i / columnCount; + int currentColumnIndex = i % columnCount; + + // If it's the first cell in the row, reset heights for the row + if (currentColumnIndex == 0) + { + maxMinimumHeightInRow = minimumRowHeight; + maxPreferredHeightInRow = minimumRowHeight; + } + + maxPreferredHeightInRow = Mathf.Max(LayoutUtility.GetPreferredHeight(rectChildren[i]), maxPreferredHeightInRow); + maxMinimumHeightInRow = Mathf.Max(LayoutUtility.GetMinHeight(rectChildren[i]), maxMinimumHeightInRow); + + // If it's the last cell in the row, or if it's the last cell and the row is incomplete, set calculated heights + if (currentColumnIndex == columnCount - 1 || (i == rectChildren.Count - 1 && currentRowIndex == rowCount - 1)) + { + totalMinHeight += maxMinimumHeightInRow; + totalPreferredHeight += maxPreferredHeightInRow; + + // Add calculated row height to a commonly accessible array for reuse in SetLayoutVertical() + preferredRowHeights[currentRowIndex] = maxPreferredHeightInRow; + } + } + } + else + { + // If flexibleRowHeight is disabled, then use the minimumRowHeight to calculate vertical layout information + for (int i = 0; i < rowCount; i++) + preferredRowHeights[i] = minimumRowHeight; + + totalMinHeight += rowCount * minimumRowHeight; + totalPreferredHeight = totalMinHeight; + } + + totalPreferredHeight = Mathf.Max(totalMinHeight, totalPreferredHeight); + SetLayoutInputForAxis(totalMinHeight, totalPreferredHeight, 1, 1); + } + + public override void SetLayoutHorizontal() + { + // If no column width is defined, then assign a reasonable default + if (columnWidths.Length == 0) + columnWidths = new float[1] { 0f }; + + int columnCount = columnWidths.Length; + int cornerX = (int)startCorner % 2; + + float startOffset = 0; + float requiredSizeWithoutPadding = 0; + + // We calculate the actual cell count for cases where the number of children is lesser than the number of columns + int actualCellCount = Mathf.Min(rectChildren.Count, columnWidths.Length); + + for (int i = 0; i < actualCellCount; i++) + { + requiredSizeWithoutPadding += columnWidths[i]; + requiredSizeWithoutPadding += columnSpacing; + } + + requiredSizeWithoutPadding -= columnSpacing; + + startOffset = GetStartOffset(0, requiredSizeWithoutPadding); + + if (cornerX == 1) + startOffset += requiredSizeWithoutPadding; + + float positionX = startOffset; + + for (int i = 0; i < rectChildren.Count; i++) + { + int currentColumnIndex = i % columnCount; + + // If it's the first cell in the row, reset positionX + if (currentColumnIndex == 0) + positionX = startOffset; + + if (cornerX == 1) + positionX -= columnWidths[currentColumnIndex]; + + SetChildAlongAxis(rectChildren[i], 0, positionX, columnWidths[currentColumnIndex]); + + if (cornerX == 1) + positionX -= columnSpacing; + else + positionX += columnWidths[currentColumnIndex] + columnSpacing; + } + } + + public override void SetLayoutVertical() + { + int columnCount = columnWidths.Length; + int rowCount = preferredRowHeights.Length; + + int cornerY = (int)startCorner / 2; + + float startOffset = 0; + float requiredSizeWithoutPadding = 0; + + for (int i = 0; i < rowCount; i++) + { + requiredSizeWithoutPadding += preferredRowHeights[i]; + requiredSizeWithoutPadding += rowSpacing; + } + + requiredSizeWithoutPadding -= rowSpacing; + + startOffset = GetStartOffset(1, requiredSizeWithoutPadding); + + if (cornerY == 1) + startOffset += requiredSizeWithoutPadding; + + float positionY = startOffset; + + for (int i = 0; i < rectChildren.Count; i++) + { + int currentRowIndex = i / columnCount; + int currentColumnIndex = i % columnCount; + + // If it's the first cell in the row and start corner is one of the bottom corners, then modify positionY appropriately + if (currentColumnIndex == 0 && cornerY == 1) + positionY -= preferredRowHeights[currentRowIndex]; + + SetChildAlongAxis(rectChildren[i], 1, positionY, preferredRowHeights[currentRowIndex]); + + // If it's the first last cell in the row, then modify positionY appropriately + if (currentColumnIndex == columnCount - 1) + { + if (cornerY == 1) + positionY -= rowSpacing; + else + positionY += preferredRowHeights[currentRowIndex] + rowSpacing; + } + } + + // Set preferredRowHeights to null to free memory + preferredRowHeights = null; + } + } } \ No newline at end of file diff --git a/Scripts/Layout/TableLayoutGroup.cs.meta b/Scripts/Layout/TableLayoutGroup.cs.meta new file mode 100644 index 0000000..f96aa4c --- /dev/null +++ b/Scripts/Layout/TableLayoutGroup.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6cee1f3bb43ca9c4c9e00b54a998d9ce +timeCreated: 1483117134 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: