From 1fb1f0241ed807b869b99ce063f240f8a139b2ee Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Mon, 4 Jan 2021 23:37:55 +0800 Subject: [PATCH] add source code --- .../Controls/Panel/UniformSpacingPanel.cs | 280 ++++++++++++++++++ .../Data/Enum/VisualWrapping.cs | 8 + .../HandyControl_Shared.projitems | 2 + 3 files changed, 290 insertions(+) create mode 100644 src/Shared/HandyControl_Shared/Controls/Panel/UniformSpacingPanel.cs create mode 100644 src/Shared/HandyControl_Shared/Data/Enum/VisualWrapping.cs diff --git a/src/Shared/HandyControl_Shared/Controls/Panel/UniformSpacingPanel.cs b/src/Shared/HandyControl_Shared/Controls/Panel/UniformSpacingPanel.cs new file mode 100644 index 00000000..289e80c7 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Panel/UniformSpacingPanel.cs @@ -0,0 +1,280 @@ +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using HandyControl.Data; +using HandyControl.Expression.Drawing; +using HandyControl.Tools; + +namespace HandyControl.Controls +{ + public class UniformSpacingPanel : Panel + { + private Orientation _orientation; + + public UniformSpacingPanel() + { + _orientation = Orientation.Horizontal; + } + + public static readonly DependencyProperty OrientationProperty = + StackPanel.OrientationProperty.AddOwner(typeof(UniformSpacingPanel), + new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure, OnOrientationChanged)); + + private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var p = (UniformSpacingPanel) d; + p._orientation = (Orientation) e.NewValue; + } + + public Orientation Orientation + { + get => (Orientation) GetValue(OrientationProperty); + set => SetValue(OrientationProperty, value); + } + + public static readonly DependencyProperty ChildWrappingProperty = DependencyProperty.Register( + "ChildWrapping", typeof(VisualWrapping), typeof(UniformSpacingPanel), + new FrameworkPropertyMetadata(default(VisualWrapping), FrameworkPropertyMetadataOptions.AffectsMeasure)); + + public VisualWrapping ChildWrapping + { + get => (VisualWrapping) GetValue(ChildWrappingProperty); + set => SetValue(ChildWrappingProperty, value); + } + + public static readonly DependencyProperty SpacingProperty = DependencyProperty.Register( + "Spacing", typeof(double), typeof(UniformSpacingPanel), + new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsMeasure), + ValidateHelper.IsInRangeOfPosDoubleIncludeZero); + + public double Spacing + { + get => (double) GetValue(SpacingProperty); + set => SetValue(SpacingProperty, value); + } + + public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register( + "ItemWidth", typeof(double), typeof(UniformSpacingPanel), + new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure), + IsWidthHeightValid); + + [TypeConverter(typeof(LengthConverter))] + public double ItemWidth + { + get => (double) GetValue(ItemWidthProperty); + set => SetValue(ItemWidthProperty, value); + } + + public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register( + "ItemHeight", typeof(double), typeof(UniformSpacingPanel), + new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure), + IsWidthHeightValid); + + [TypeConverter(typeof(LengthConverter))] + public double ItemHeight + { + get => (double) GetValue(ItemHeightProperty); + set => SetValue(ItemHeightProperty, value); + } + + private static bool IsWidthHeightValid(object value) + { + var v = (double) value; + return double.IsNaN(v) || v >= 0.0d && !double.IsPositiveInfinity(v); + } + + private void ArrangeLine(double v, double lineV, int start, int end, bool useItemU, double itemU, double spacing) + { + double u = 0; + var isHorizontal = _orientation == Orientation.Horizontal; + + var children = InternalChildren; + for (var i = start; i < end; i++) + { + var child = children[i]; + if (child == null) continue; + + var childSize = new UVSize(_orientation, child.DesiredSize.Width, child.DesiredSize.Height); + var layoutSlotU = useItemU ? itemU : childSize.U; + + child.Arrange(isHorizontal ? new Rect(u, v, layoutSlotU, lineV) : new Rect(v, u, lineV, layoutSlotU)); + + u += layoutSlotU + spacing; + } + } + + protected override Size MeasureOverride(Size constraint) + { + var curLineSize = new UVSize(_orientation); + var panelSize = new UVSize(_orientation); + var uvConstraint = new UVSize(_orientation, constraint.Width, constraint.Height); + var itemWidth = ItemWidth; + var itemHeight = ItemHeight; + var itemWidthSet = !double.IsNaN(itemWidth); + var itemHeightSet = !double.IsNaN(itemHeight); + var spacing = Spacing; + var childWrapping = ChildWrapping; + + var childConstraint = new Size( + itemWidthSet ? itemWidth : constraint.Width, + itemHeightSet ? itemHeight : constraint.Height); + + var children = InternalChildren; + var isFirst = true; + + for (int i = 0, count = children.Count; i < count; i++) + { + var child = children[i]; + if (child == null) continue; + + child.Measure(childConstraint); + + var sz = new UVSize( + _orientation, + itemWidthSet ? itemWidth : child.DesiredSize.Width, + itemHeightSet ? itemHeight : child.DesiredSize.Height); + + if (childWrapping == VisualWrapping.Wrap && MathHelper.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) + { + panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.V += curLineSize.V + spacing; + curLineSize = sz; + + if (MathHelper.GreaterThan(sz.U, uvConstraint.U)) + { + panelSize.U = Math.Max(sz.U, panelSize.U); + panelSize.V += sz.V + spacing; + curLineSize = new UVSize(_orientation); + } + + isFirst = true; + } + else + { + curLineSize.U += isFirst ? sz.U : sz.U + spacing; + isFirst = false; + curLineSize.V = Math.Max(sz.V, curLineSize.V); + } + } + + panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.V += curLineSize.V; + + return new Size(panelSize.Width, panelSize.Height); + } + + protected override Size ArrangeOverride(Size finalSize) + { + var firstInLine = 0; + var itemWidth = ItemWidth; + var itemHeight = ItemHeight; + double accumulatedV = 0; + var itemU = _orientation == Orientation.Horizontal ? itemWidth : itemHeight; + var curLineSize = new UVSize(_orientation); + var uvFinalSize = new UVSize(_orientation, finalSize.Width, finalSize.Height); + var itemWidthSet = !double.IsNaN(itemWidth); + var itemHeightSet = !double.IsNaN(itemHeight); + var useItemU = _orientation == Orientation.Horizontal ? itemWidthSet : itemHeightSet; + var spacing = Spacing; + var childWrapping = ChildWrapping; + + var children = InternalChildren; + + for (int i = 0, count = children.Count; i < count; i++) + { + var child = children[i]; + if (child == null) continue; + + var sz = new UVSize( + _orientation, + itemWidthSet ? itemWidth : child.DesiredSize.Width, + itemHeightSet ? itemHeight : child.DesiredSize.Height); + + if (childWrapping == VisualWrapping.Wrap && MathHelper.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) + { + ArrangeLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU, spacing); + + accumulatedV += curLineSize.V + spacing; + curLineSize = sz; + + if (MathHelper.GreaterThan(sz.U, uvFinalSize.U)) + { + ArrangeLine(accumulatedV, sz.V, i, ++i, useItemU, itemU, spacing); + + accumulatedV += sz.V + spacing; + curLineSize = new UVSize(_orientation); + } + firstInLine = i; + } + else + { + curLineSize.U += sz.U; + curLineSize.V = Math.Max(sz.V, curLineSize.V); + } + } + + if (firstInLine < children.Count) + { + ArrangeLine(accumulatedV, curLineSize.V, firstInLine, children.Count, useItemU, itemU, spacing); + } + + return finalSize; + } + + private struct UVSize + { + internal UVSize(Orientation orientation, double width, double height) + { + U = V = 0d; + _orientation = orientation; + Width = width; + Height = height; + } + + internal UVSize(Orientation orientation) + { + U = V = 0d; + _orientation = orientation; + } + + public double U { get; set; } + + public double V { get; set; } + + private readonly Orientation _orientation; + + public double Width + { + get => _orientation == Orientation.Horizontal ? U : V; + private set + { + if (_orientation == Orientation.Horizontal) + { + U = value; + } + else + { + V = value; + } + } + } + + public double Height + { + get => _orientation == Orientation.Horizontal ? V : U; + private set + { + if (_orientation == Orientation.Horizontal) + { + V = value; + } + else + { + U = value; + } + } + } + } + } +} diff --git a/src/Shared/HandyControl_Shared/Data/Enum/VisualWrapping.cs b/src/Shared/HandyControl_Shared/Data/Enum/VisualWrapping.cs new file mode 100644 index 00000000..02631d6e --- /dev/null +++ b/src/Shared/HandyControl_Shared/Data/Enum/VisualWrapping.cs @@ -0,0 +1,8 @@ +namespace HandyControl.Data +{ + public enum VisualWrapping + { + NoWrap, + Wrap + } +} diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index 5bc91cfa..c6afb938 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -47,6 +47,7 @@ + @@ -77,6 +78,7 @@ +