diff --git a/AetherBags/Nodes/WrappingGridNode.cs b/AetherBags/Nodes/WrappingGridNode.cs index 9b11941..416bdd3 100644 --- a/AetherBags/Nodes/WrappingGridNode.cs +++ b/AetherBags/Nodes/WrappingGridNode.cs @@ -1,72 +1,137 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using KamiToolKit; using KamiToolKit. Nodes; namespace AetherBags.Nodes { - public class WrappingGridNode : LayoutListNode where T : NodeBase + public sealed class WrappingGridNode : LayoutListNode where T : NodeBase { - public float HorizontalSpacing { get; set; } = 10; - public float VerticalSpacing { get; set; } = 10; - private List> _rows = new(); + public float HorizontalSpacing { get; set; } = 10f; + public float VerticalSpacing { get; set; } = 10f; + + private readonly List> _rows = new(); + private readonly Stack> _rowPool = new(); + + private float _requiredHeight; + private bool _requiredHeightDirty = true; protected override void InternalRecalculateLayout() { - if (NodeList. Count == 0) - return; + RecycleAllRows(); - _rows.Clear(); + int count = NodeList.Count; + if (count == 0) + { + _requiredHeight = 0f; + _requiredHeightDirty = false; + return; + } float availableWidth = Width; - float currentX = 0f; + float hSpace = HorizontalSpacing; + float vSpace = VerticalSpacing; + float startX = FirstItemSpacing; + + float currentX = startX; float currentY = 0f; float rowHeight = 0f; - List currentRow = new(); - foreach (var node in NodeList) + List currentRow = RentRowList(capacityHint: 8); + + for (int i = 0; i < count; i++) { - float nodeWidth = node.Width; - float nodeHeight = node.Height; + NodeBase node = NodeList[i]; - if (currentX + nodeWidth > availableWidth && currentRow.Count > 0) + float nodeWidth = node.Width; + + if (currentRow.Count != 0 && (currentX + nodeWidth) > availableWidth) { _rows.Add(currentRow); - currentRow = new(); - currentY += rowHeight + VerticalSpacing; - currentX = 0f; + + currentY += rowHeight + vSpace; + currentX = startX; rowHeight = 0f; + + currentRow = RentRowList(capacityHint: 8); } node.X = currentX; - node. Y = currentY; + node.Y = currentY; + AdjustNode(node); - currentX += nodeWidth + HorizontalSpacing; - rowHeight = Math.Max(rowHeight, nodeHeight); + float nodeHeight = node.Height; + if (nodeHeight > rowHeight) rowHeight = nodeHeight; + currentRow.Add(node); + + currentX += nodeWidth + hSpace; } - if (currentRow.Count > 0) + if (currentRow.Count != 0) { _rows.Add(currentRow); } - } - - public float GetRequiredHeight() - { - if (NodeList.Count == 0) - return 0f; - - float maxY = 0f; - foreach (var node in NodeList) + else { - float nodeBottom = node.Y + node.Height; - maxY = Math. Max(maxY, nodeBottom); + RecycleRow(currentRow); } - return maxY; + _requiredHeightDirty = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float GetRequiredHeight() + { + if (!_requiredHeightDirty) return _requiredHeight; + + float maxBottom = 0f; + int count = NodeList.Count; + + for (int i = 0; i < count; i++) + { + NodeBase node = NodeList[i]; + float bottom = node.Y + node.Height; + if (bottom > maxBottom) maxBottom = bottom; + } + + _requiredHeight = maxBottom; + _requiredHeightDirty = false; + return maxBottom; + } + + private void RecycleAllRows() + { + for (int i = 0; i < _rows.Count; i++) + { + List row = _rows[i]; + row.Clear(); + _rowPool.Push(row); + } + _rows.Clear(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private List RentRowList(int capacityHint) + { + if (_rowPool.Count != 0) + { + List row = _rowPool.Pop(); + if (row.Capacity < capacityHint) row.Capacity = capacityHint; + return row; + } + + return new List(capacityHint); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void RecycleRow(List row) + { + row.Clear(); + _rowPool.Push(row); } } } \ No newline at end of file