Files
HandyControl/src/Shared/HandyControl_Shared/Controls/Panel/WaterfallPanel.cs
T
2021-09-14 23:41:35 +08:00

150 lines
5.1 KiB
C#

using System.Linq;
using System.Windows;
using System.Windows.Controls;
using HandyControl.Data;
using HandyControl.Expression.Drawing;
using HandyControl.Tools;
namespace HandyControl.Controls
{
public class WaterfallPanel : Panel
{
public static readonly DependencyProperty GroupsProperty = DependencyProperty.Register(
"Groups", typeof(int), typeof(WaterfallPanel), new FrameworkPropertyMetadata(
ValueBoxes.Int2Box, FrameworkPropertyMetadataOptions.AffectsMeasure), IsGroupsValid);
public int Groups
{
get => (int) GetValue(GroupsProperty);
set => SetValue(GroupsProperty, value);
}
private static bool IsGroupsValid(object value) => (int) value >= 1;
public static readonly DependencyProperty AutoGroupProperty = DependencyProperty.Register(
"AutoGroup", typeof(bool), typeof(WaterfallPanel), new FrameworkPropertyMetadata(
ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsMeasure));
public bool AutoGroup
{
get => (bool) GetValue(AutoGroupProperty);
set => SetValue(AutoGroupProperty, ValueBoxes.BooleanBox(value));
}
public static readonly DependencyProperty DesiredLengthProperty = DependencyProperty.Register(
"DesiredLength", typeof(double), typeof(WaterfallPanel), new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
FrameworkPropertyMetadataOptions.AffectsMeasure), ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
public double DesiredLength
{
get => (double) GetValue(DesiredLengthProperty);
set => SetValue(DesiredLengthProperty, value);
}
public static readonly DependencyProperty OrientationProperty =
StackPanel.OrientationProperty.AddOwner(typeof(WaterfallPanel),
new FrameworkPropertyMetadata(Orientation.Horizontal,
FrameworkPropertyMetadataOptions.AffectsMeasure));
public Orientation Orientation
{
get => (Orientation) GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
private int CaculateGroupCount(Orientation orientation, PanelUvSize size)
{
if (!AutoGroup)
{
return Groups;
}
var itemLength = DesiredLength;
if (MathHelper.IsVerySmall(itemLength))
{
return Groups;
}
return (int) (size.U / itemLength);
}
protected override Size ArrangeOverride(Size finalSize)
{
var orientation = Orientation;
var uvConstraint = new PanelUvSize(orientation, finalSize);
var groups = CaculateGroupCount(orientation, uvConstraint);
if (groups < 1)
{
return finalSize;
}
var vArr = new double[groups].ToList();
var itemU = uvConstraint.U / groups;
var children = InternalChildren;
for (int i = 0, count = children.Count; i < count; i++)
{
var child = children[i];
if (child == null)
{
continue;
}
var minIndex = vArr.IndexOf(vArr.Min());
var minV = vArr[minIndex];
var childUvSize = new PanelUvSize(orientation, child.DesiredSize);
var childSize = new PanelUvSize(orientation, itemU, childUvSize.V);
var childRectSize = new PanelUvSize(orientation, minIndex * itemU, minV);
child.Arrange(new Rect(new Point(childRectSize.U, childRectSize.V), childSize.ScreenSize));
vArr[minIndex] = minV + childUvSize.V;
}
return finalSize;
}
protected override Size MeasureOverride(Size constraint)
{
var orientation = Orientation;
var uvConstraint = new PanelUvSize(orientation, constraint);
var groups = CaculateGroupCount(orientation, uvConstraint);
if (groups < 1)
{
return constraint;
}
var vArr = new double[groups].ToList();
var itemU = uvConstraint.U / groups;
if (double.IsNaN(itemU) || double.IsInfinity(itemU))
{
return constraint;
}
var children = InternalChildren;
for (int i = 0, count = children.Count; i < count; i++)
{
var child = children[i];
if (child == null)
{
continue;
}
child.Measure(constraint);
var sz = new PanelUvSize(orientation, child.DesiredSize);
var minIndex = vArr.IndexOf(vArr.Min());
var minV = vArr[minIndex];
vArr[minIndex] = minV + sz.V;
}
uvConstraint = new PanelUvSize(orientation, new Size(uvConstraint.ScreenSize.Width, vArr.Max()));
return uvConstraint.ScreenSize;
}
}
}