Skip to content

Instantly share code, notes, and snippets.

@JohanLarsson
Created March 18, 2022 07:48
Show Gist options
  • Save JohanLarsson/8be644ba43098c912034e839843d15f0 to your computer and use it in GitHub Desktop.
Save JohanLarsson/8be644ba43098c912034e839843d15f0 to your computer and use it in GitHub Desktop.
public class SplitPanel : Panel
{
private double[] positions = Array.Empty<double>();
protected override Size MeasureOverride(Size availableSize)
{
if (this.positions.Length < this.InternalChildren.Count)
{
this.positions = new double[this.InternalChildren.Count];
}
var sum = 0.0;
var width = 0.0;
for (var i = 0; i < this.InternalChildren.Count; i++)
{
var child = this.InternalChildren[i];
child.Measure(availableSize);
sum += child.DesiredSize.Height;
width = Math.Max(width, child.DesiredSize.Width);
}
this.positions[0] = 0;
if (sum <= availableSize.Height)
{
for (var i = 0; i < this.InternalChildren.Count - 1; i++)
{
this.positions[i + 1] = this.positions[i] + this.InternalChildren[i].DesiredSize.Height;
}
return new Size(
Math.Min(availableSize.Width, width),
sum);
}
var maxHeight = MaxHeight();
for (var i = 0; i < this.InternalChildren.Count; i++)
{
var child = this.InternalChildren[i];
if (child.DesiredSize.Height > maxHeight)
{
child.Measure(new Size(availableSize.Width, maxHeight));
}
if (i < this.InternalChildren.Count - 1)
{
this.positions[i + 1] = this.positions[i] + Math.Min(this.InternalChildren[i].DesiredSize.Height, maxHeight);
}
}
return new Size(
Math.Min(availableSize.Width, width),
availableSize.Height);
double MaxHeight()
{
var children = ListCache.Borrow(this.InternalChildren);
var remaining = availableSize.Height;
while (FindSmall() is { } small)
{
children.Remove(small);
remaining -= small.DesiredSize.Height;
}
return remaining / ListCache.Return(children);
UIElement? FindSmall()
{
if (children.Count < 2)
{
return null;
}
foreach (var child in children)
{
if (child.DesiredSize.Height < remaining / children.Count)
{
return child;
}
}
return null;
}
}
}
protected override Size ArrangeOverride(Size finalSize)
{
for (var i = 0; i < this.InternalChildren.Count; i++)
{
this.InternalChildren[i].Arrange(
new Rect(
0,
this.positions[i],
finalSize.Width,
Height()));
double Height()
{
if (i < this.InternalChildren.Count - 1)
{
return this.positions[i + 1] - this.positions[i];
}
return finalSize.Height - this.positions[^1];
}
}
return finalSize;
}
private static class ListCache
{
private static List<UIElement>? cached = new();
internal static List<UIElement> Borrow(UIElementCollection elements)
{
var list = cached ?? throw new InvalidOperationException("Not returned?");
cached = null;
for (var i = 0; i < elements.Count; i++)
{
list.Add(elements[i]);
}
return list;
}
internal static int Return(List<UIElement> list)
{
var count = list.Count;
list.Clear();
cached = list;
return count;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment