176 lines
4.1 KiB
C#
176 lines
4.1 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace KitsuneCafe.UI
|
|
{
|
|
public record LayoutItem(float Position, float Size)
|
|
{
|
|
public float Min => Position;
|
|
public float Max => Position + Size;
|
|
}
|
|
|
|
public class DynamicLayout : ILayout, IEnumerable<LayoutItem>
|
|
{
|
|
|
|
public struct LayoutEnumerator : IEnumerator<LayoutItem>
|
|
{
|
|
public readonly int Start;
|
|
public int Index;
|
|
private readonly DynamicLayout layout;
|
|
|
|
public LayoutEnumerator(int index, DynamicLayout layout)
|
|
{
|
|
Start = index;
|
|
Index = index;
|
|
this.layout = layout;
|
|
}
|
|
|
|
public LayoutEnumerator(DynamicLayout layout) : this(0, layout) { }
|
|
|
|
public readonly LayoutItem Current => new(
|
|
layout.positions[Index - 1],
|
|
layout.sizes[Index - 1]
|
|
);
|
|
|
|
readonly object IEnumerator.Current => Current;
|
|
|
|
public readonly void Dispose() { }
|
|
|
|
public bool MoveNext()
|
|
{
|
|
Index += 1;
|
|
return Index < layout.positions.Count;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
Index = Start;
|
|
}
|
|
}
|
|
|
|
public float DefaultItemSize { get; set; }
|
|
public float GutterSize { get; set; }
|
|
public FlowDirection Direction { get; set; }
|
|
public float ContentSize { get; private set; }
|
|
|
|
private readonly List<float> positions = new();
|
|
private readonly List<float> sizes = new();
|
|
|
|
public DynamicLayout(FlowDirection direction, float defaultItemSize = 22, float gutterSize = 0)
|
|
{
|
|
Direction = direction;
|
|
GutterSize = gutterSize;
|
|
DefaultItemSize = defaultItemSize;
|
|
}
|
|
|
|
public float GetItemPosition(int index)
|
|
{
|
|
if (index > 0)
|
|
{
|
|
return GetItemPosition(index - 1) + GetItemSize(index - 1) + GutterSize;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public float GetItemSize(int index)
|
|
{
|
|
if (index >= 0 && index < sizes.Count)
|
|
{
|
|
return sizes[index];
|
|
}
|
|
|
|
return DefaultItemSize;
|
|
}
|
|
|
|
private float LastPositionOrDefault()
|
|
{
|
|
return positions.Count > 0 ? positions[^1] : DefaultItemSize + GutterSize;
|
|
}
|
|
|
|
public void Update(int itemCount, VisualElement container)
|
|
{
|
|
while (positions.Count < itemCount)
|
|
{
|
|
var last = LastPositionOrDefault();
|
|
positions.Add(last + DefaultItemSize + GutterSize);
|
|
sizes.Add(DefaultItemSize);
|
|
}
|
|
|
|
if (positions.Count > itemCount)
|
|
{
|
|
positions.RemoveRange(itemCount, positions.Count - itemCount);
|
|
sizes.RemoveRange(itemCount, sizes.Count - itemCount);
|
|
}
|
|
|
|
ContentSize = LastPositionOrDefault();
|
|
}
|
|
|
|
private float CalculatePositions(int startingIndex = 0, float initialPosition = 0)
|
|
{
|
|
var position = initialPosition;
|
|
|
|
for (int i = startingIndex; i < positions.Count; i++)
|
|
{
|
|
positions[i] = position;
|
|
position += GetItemSize(i) + GutterSize;
|
|
}
|
|
|
|
return ContentSize = position;
|
|
}
|
|
|
|
public void SetMeasuredItemSize(int index, float size)
|
|
{
|
|
if (index < sizes.Count && Mathf.Approximately(sizes[index], size))
|
|
{
|
|
return;
|
|
}
|
|
|
|
sizes[index] = size;
|
|
|
|
var position = index > 0 ? positions[index - 1] + sizes[index - 1] + GutterSize : 0;
|
|
CalculatePositions(index, position);
|
|
}
|
|
|
|
public int GetFirstVisibleIndex(float scrollOffset)
|
|
{
|
|
if (scrollOffset <= 0) { return 0; }
|
|
|
|
for (int i = 0; i < positions.Count; i++)
|
|
{
|
|
if (positions[i] >= scrollOffset)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return positions.Count - 1;
|
|
}
|
|
|
|
public IEnumerable<LayoutItem> Enumerate(int startIndex = 0)
|
|
{
|
|
var len = positions.Count;
|
|
for (int i = startIndex; i < len; i++)
|
|
{
|
|
yield return new LayoutItem(positions[i], sizes[i]);
|
|
}
|
|
}
|
|
|
|
public IEnumerator<LayoutItem> GetEnumerator()
|
|
{
|
|
return new LayoutEnumerator(this);
|
|
}
|
|
|
|
public IEnumerator<LayoutItem> GetEnumerator(int startIndex)
|
|
{
|
|
return new LayoutEnumerator(startIndex, this);
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
}
|
|
}
|