Created
March 18, 2022 07:48
-
-
Save JohanLarsson/8be644ba43098c912034e839843d15f0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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