From 4f16723cd55f4ee299dd13bd8396feb899a2c251 Mon Sep 17 00:00:00 2001 From: Zhang Dian <54255897+zdpcdt@users.noreply.github.com> Date: Thu, 7 Sep 2023 15:31:39 +0800 Subject: [PATCH 01/15] feat: initial ElasticWrapPanel. --- demo/Ursa.Demo/Models/MenuKeys.cs | 1 + .../Pages/ElasticWrapPanelDemo.axaml | 12 +++++++ .../Pages/ElasticWrapPanelDemo.axaml.cs | 13 ++++++++ .../ElasticWrapPanelDemoViewModel.cs | 7 ++++ .../Ursa.Demo/ViewModels/MainViewViewModel.cs | 1 + demo/Ursa.Demo/ViewModels/MenuViewModel.cs | 1 + .../Controls/ElasticWrapPanel.axaml | 3 ++ src/Ursa.Themes.Semi/Controls/_index.axaml | 1 + src/Ursa/Controls/ElasticWrapPanel.cs | 33 +++++++++++++++++++ 9 files changed, 72 insertions(+) create mode 100644 demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml create mode 100644 demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml.cs create mode 100644 demo/Ursa.Demo/ViewModels/ElasticWrapPanelDemoViewModel.cs create mode 100644 src/Ursa.Themes.Semi/Controls/ElasticWrapPanel.axaml create mode 100644 src/Ursa/Controls/ElasticWrapPanel.cs diff --git a/demo/Ursa.Demo/Models/MenuKeys.cs b/demo/Ursa.Demo/Models/MenuKeys.cs index 8faf23a..fdf1286 100644 --- a/demo/Ursa.Demo/Models/MenuKeys.cs +++ b/demo/Ursa.Demo/Models/MenuKeys.cs @@ -7,6 +7,7 @@ public static class MenuKeys public const string MenuKeyButtonGroup = "ButtonGroup"; public const string MenuKeyDivider = "Divider"; public const string MenuKeyDualBadge = "DualBadge"; + public const string MenuKeyElasticWrapPanel = "ElasticWrapPanel"; public const string MenuKeyIpBox = "IPv4Box"; public const string MenuKeyKeyGestureInput = "KeyGestureInput"; public const string MenuKeyLoading = "Loading"; diff --git a/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml b/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml new file mode 100644 index 0000000..cbe4dfc --- /dev/null +++ b/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml.cs b/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml.cs new file mode 100644 index 0000000..fde0e8e --- /dev/null +++ b/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Ursa.Demo.Pages; + +public partial class ElasticWrapPanelDemo : UserControl +{ + public ElasticWrapPanelDemo() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/demo/Ursa.Demo/ViewModels/ElasticWrapPanelDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/ElasticWrapPanelDemoViewModel.cs new file mode 100644 index 0000000..9910657 --- /dev/null +++ b/demo/Ursa.Demo/ViewModels/ElasticWrapPanelDemoViewModel.cs @@ -0,0 +1,7 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace Ursa.Demo.ViewModels; + +public class ElasticWrapPanelDemoViewModel : ObservableObject +{ +} \ No newline at end of file diff --git a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs index 8487910..559e53d 100644 --- a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs @@ -29,6 +29,7 @@ public class MainViewViewModel : ViewModelBase MenuKeys.MenuKeyButtonGroup => new ButtonGroupDemoViewModel(), MenuKeys.MenuKeyDivider => new DividerDemoViewModel(), MenuKeys.MenuKeyDualBadge => new DualBadgeDemoViewModel(), + MenuKeys.MenuKeyElasticWrapPanel => new ElasticWrapPanelDemoViewModel(), MenuKeys.MenuKeyIpBox => new IPv4BoxDemoViewModel(), MenuKeys.MenuKeyKeyGestureInput => new KeyGestureInputDemoViewModel(), MenuKeys.MenuKeyLoading => new LoadingDemoViewModel(), diff --git a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs index f55365f..57aa4f4 100644 --- a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs +++ b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs @@ -16,6 +16,7 @@ public class MenuViewModel: ViewModelBase new() { MenuHeader = "ButtonGroup", Key = MenuKeys.MenuKeyButtonGroup }, new() { MenuHeader = "Divider", Key = MenuKeys.MenuKeyDivider }, new() { MenuHeader = "DualBadge", Key = MenuKeys.MenuKeyDualBadge }, + new() { MenuHeader = "ElasticWrapPanel", Key = MenuKeys.MenuKeyElasticWrapPanel }, new() { MenuHeader = "IPv4Box", Key = MenuKeys.MenuKeyIpBox }, new() { MenuHeader = "KeyGestureInput", Key = MenuKeys.MenuKeyKeyGestureInput }, new() { MenuHeader = "Loading", Key = MenuKeys.MenuKeyLoading }, diff --git a/src/Ursa.Themes.Semi/Controls/ElasticWrapPanel.axaml b/src/Ursa.Themes.Semi/Controls/ElasticWrapPanel.axaml new file mode 100644 index 0000000..fecc72d --- /dev/null +++ b/src/Ursa.Themes.Semi/Controls/ElasticWrapPanel.axaml @@ -0,0 +1,3 @@ + + diff --git a/src/Ursa.Themes.Semi/Controls/_index.axaml b/src/Ursa.Themes.Semi/Controls/_index.axaml index 2038cd0..75c025d 100644 --- a/src/Ursa.Themes.Semi/Controls/_index.axaml +++ b/src/Ursa.Themes.Semi/Controls/_index.axaml @@ -6,6 +6,7 @@ + diff --git a/src/Ursa/Controls/ElasticWrapPanel.cs b/src/Ursa/Controls/ElasticWrapPanel.cs new file mode 100644 index 0000000..285235e --- /dev/null +++ b/src/Ursa/Controls/ElasticWrapPanel.cs @@ -0,0 +1,33 @@ +using Avalonia; +using Avalonia.Controls; + +namespace Ursa.Controls; + +public class ElasticWrapPanel : Panel +{ + protected override Size MeasureOverride(Size availableSize) + { + var panelDesiredSize = new Size(); + + foreach (var child in Children) + { + child.Measure(availableSize); + panelDesiredSize = child.DesiredSize; + } + + return panelDesiredSize; + } + + protected override Size ArrangeOverride(Size finalSize) + { + foreach (var child in Children) + { + const double x = 50; + const double y = 50; + + child.Arrange(new Rect(new Point(x, y), child.DesiredSize)); + } + + return finalSize; + } +} \ No newline at end of file From 0caa85aff45a33b2f73fcef8257d5052512cbdb6 Mon Sep 17 00:00:00 2001 From: Zhang Dian <54255897+zdpcdt@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:57:01 +0800 Subject: [PATCH 02/15] feat: ElasticWrapPanel. --- src/Ursa/Controls/ElasticWrapPanel.cs | 500 +++++++++++++++++++++++++- 1 file changed, 489 insertions(+), 11 deletions(-) diff --git a/src/Ursa/Controls/ElasticWrapPanel.cs b/src/Ursa/Controls/ElasticWrapPanel.cs index 285235e..7d7b3ef 100644 --- a/src/Ursa/Controls/ElasticWrapPanel.cs +++ b/src/Ursa/Controls/ElasticWrapPanel.cs @@ -1,33 +1,511 @@ using Avalonia; using Avalonia.Controls; +using Avalonia.Layout; +using Avalonia.Utilities; namespace Ursa.Controls; -public class ElasticWrapPanel : Panel +public class ElasticWrapPanel : WrapPanel { + static ElasticWrapPanel() + { + IsFillHorizontalProperty.Changed.AddClassHandler(OnIsFillPropertyChanged); + IsFillHorizontalProperty.Changed.AddClassHandler(OnIsFillPropertyChanged); + + AffectsMeasure(IsFillHorizontalProperty, IsFillHorizontalProperty); + } + + #region AttachedProperty + + public static void SetFixToRB(Control element, bool value) + { + _ = element ?? throw new ArgumentNullException(nameof(element)); + element.SetValue(FixToRBProperty, value); + } + + public static bool GetIsFixToRB(Control element) + { + _ = element ?? throw new ArgumentNullException(nameof(element)); + return element.GetValue(FixToRBProperty); + } + + /// + /// Fixed to [Right (Horizontal Mode) | Bottom (Vertical Mode)] + /// which will cause line breaks + /// + public static readonly AttachedProperty FixToRBProperty = + AvaloniaProperty.RegisterAttached("FixToRB"); + + #endregion + + #region StyledProperty + + public bool IsFillHorizontal + { + get => GetValue(IsFillHorizontalProperty); + set => SetValue(IsFillHorizontalProperty, value); + } + + public static readonly StyledProperty IsFillHorizontalProperty = + AvaloniaProperty.Register(nameof(IsFillHorizontal)); + + public bool IsFillVertical + { + get => GetValue(IsFillVerticalProperty); + set => SetValue(IsFillVerticalProperty, value); + } + + public static readonly StyledProperty IsFillVerticalProperty = + AvaloniaProperty.Register(nameof(IsFillVertical)); + + private static void OnIsFillPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) + { + (d as ElasticWrapPanel)?.InvalidateMeasure(); + } + + #endregion + protected override Size MeasureOverride(Size availableSize) { - var panelDesiredSize = new Size(); + //是否元素宽度设置,是否元素高度设置 + bool isItemWidthSet = !double.IsNaN(this.ItemWidth) && this.ItemWidth > 0; + bool isItemHeightSet = !double.IsNaN(this.ItemHeight) && this.ItemHeight > 0; - foreach (var child in Children) + //非FixToRB=True元素使用测量需求空间Size + Size childConstraint = new Size( + (isItemWidthSet ? this.ItemWidth : availableSize.Width), + (isItemHeightSet ? this.ItemHeight : availableSize.Height)); + + //FixToRB=True元素使用测量需求空间Size + Size childFixConstraint = new Size(availableSize.Width, availableSize.Height); + if (Orientation == Orientation.Horizontal && isItemHeightSet) { - child.Measure(availableSize); - panelDesiredSize = child.DesiredSize; + childFixConstraint = new Size(availableSize.Width, this.ItemHeight); } - return panelDesiredSize; + if (Orientation == Orientation.Vertical && isItemWidthSet) + { + childFixConstraint = new Size(this.ItemWidth, this.ItemHeight); + } + + + //这个给非空间测量大小 + UVSize itemSetSize = new UVSize(this.Orientation, + (isItemWidthSet ? this.ItemWidth : 0), + (isItemHeightSet ? this.ItemHeight : 0)); + + //给定的空间大小测量UVSize,用于没有ItemWidth和ItemHeight时候测量元素空间大小, FixToRB=True的元素也使用这个 + UVSize uvConstraint = new UVSize(Orientation, availableSize.Width, availableSize.Height); + //将元素按照水平/垂直排列的方式得出同一行/列所需的空间需求 + UVSize curLineSize = new UVSize(Orientation); + //计算处此ElasticWrapPanel所需的空间大小需求结果 + UVSize desireResultSize = new UVSize(Orientation); + + var children = Children; + for (int i = 0, count = children.Count; i < count; i++) + { + var child = children[i]; + UVSize uvSize; + if (ElasticWrapPanel.GetIsFixToRB(child)) + { + //此元素需要设置到固定靠右/底的型为操作,测量元素大小时需要放开 + child.Measure(childFixConstraint); + uvSize = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); + + //主要是我对与这个固定住的元素的需求宽度高度按照那个标准有点头疼,干脆放开用最大控件算了 + if (uvSize.U > 0 && itemSetSize.U > 0) + { + if (uvSize.U < itemSetSize.U) + { + //保持比例 + uvSize.U = itemSetSize.U; + } + else + { + //设置了同方向中元素的长度,所以这里要按照比例 + //double lengthCount = Math.Ceiling(sz.U / ItemSetSize.U); + //sz.U = lengthCount * ItemSetSize.U; + //这里防止意外 + uvSize.U = Math.Min(uvSize.U, uvConstraint.U); + } + } + + if (uvSize.V > 0 && itemSetSize.V > 0 && uvSize.V < itemSetSize.V) + { + //设置了垂直方向元素长度,如果此元素空间需求小于,则按照ItemSetSize.V + uvSize.V = itemSetSize.V; + } + + if (MathUtilities.GreaterThan(curLineSize.U + uvSize.U, uvConstraint.U)) + { + //当前同一 列/行 如果容纳 此元素空间将超出 + desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); + desireResultSize.V += curLineSize.V; + + curLineSize = uvSize; + + //当前元素需要启1个新行 + desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); + desireResultSize.V += curLineSize.V; + } + + else + { + //这里是元素空间足够 填充式布局 + curLineSize.U += uvSize.U; + curLineSize.V = Math.Max(uvSize.V, curLineSize.V); + desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); + desireResultSize.V += curLineSize.V; + } + + //下一个可能是换行元素....用于存放全新1行 + curLineSize = new UVSize(Orientation); + } + else + { + //如果设置元素宽度或高度,其高度宽度尽可能按照设置值给定 + child.Measure(childConstraint); + uvSize = new UVSize(Orientation, + (isItemWidthSet ? this.ItemWidth : child.DesiredSize.Width), + (isItemHeightSet ? this.ItemHeight : child.DesiredSize.Height)); + if (MathUtilities.GreaterThan(curLineSize.U + uvSize.U, uvConstraint.U)) + { + //当前同一 列/行 如果容纳 此元素空间将超出 + desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); + desireResultSize.V += curLineSize.V; + curLineSize = uvSize; + if (MathUtilities.GreaterThan(uvSize.U, uvConstraint.U)) + { + //此元素同Orientation方向长度大于给定约束长度,则当前元素为一行 + desireResultSize.U = Math.Max(uvSize.U, desireResultSize.U); + desireResultSize.V += uvSize.V; + //用于存放全新1行宽度 + curLineSize = new UVSize(Orientation); + } + } + else + { + //当前同一 列/行 元素空间足够,可以容纳当前元素 + curLineSize.U += uvSize.U; + curLineSize.V = Math.Max(uvSize.V, curLineSize.V); + } + } + } + + //the last line size, if any should be added + desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); + desireResultSize.V += curLineSize.V; + + //go from UV space to W/H space + return new Size(desireResultSize.Width, desireResultSize.Height); } protected override Size ArrangeOverride(Size finalSize) { - foreach (var child in Children) - { - const double x = 50; - const double y = 50; + //设否元素宽的设置,是否元素高度设置 + bool isItemWidthSet = !double.IsNaN(this.ItemWidth) && this.ItemWidth > 0; + bool isItemHeightSet = !double.IsNaN(this.ItemHeight) && this.ItemHeight > 0; - child.Arrange(new Rect(new Point(x, y), child.DesiredSize)); + //这个给非空间测量大小 + UVSize itemSetSize = new UVSize(this.Orientation, + (isItemWidthSet ? this.ItemWidth : 0), + (isItemHeightSet ? this.ItemHeight : 0)); + + //给定的空间大小测量UVSize,用于没有ItemWidth和ItemHeight时候测量元素空间大小,FixToRB=True的元素也使用这个 + UVSize uvConstraint = new UVSize(Orientation, finalSize.Width, finalSize.Height); + + //用于存放同一方向的元素列/行 集合 + List lineUiCollection = new List(); + + #region 得到同一方向元素集合的集合 + + //写一个If只是用于减少外层变量,反感的请将if注释 + //if (lineUiCollection != null) + { + //当前元素集合行/列 + UVCollection curLineUis = new UVCollection(this.Orientation, itemSetSize); + + //遍历内部元素 + var children = Children; + for (int i = 0, count = children.Count; i < count; i++) + { + var child = children[i]; + // if (child.Visibility == Visibility.Collapsed) continue; + UVSize uvSize = new UVSize(); + if (ElasticWrapPanel.GetIsFixToRB(child)) + { + //此元素需要设置到固定靠右/底的型为操作,测量元素大小时需要放开 + uvSize = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); + double lengthCount = 1; + if (uvSize.U > 0 && itemSetSize.U > 0) + { + if (uvSize.U < itemSetSize.U) + { + //保持比例 + uvSize.U = itemSetSize.U; + } + else + { + //设置了同方向中元素的长度,所以这里要按照比例 + lengthCount = Math.Ceiling(uvSize.U / itemSetSize.U); + //sz.U = lengthCount * ItemSetSize.U; + uvSize.U = Math.Min(uvSize.U, uvConstraint.U); + } + } + + if (uvSize.V > 0 && itemSetSize.V > 0 && uvSize.V < itemSetSize.V) + { + //设置了垂直方向元素长度,如果此元素空间需求小于,则按照ItemSetSize.V + uvSize.V = itemSetSize.V; + } + + if (MathUtilities.GreaterThan(curLineUis.TotalU + uvSize.U, uvConstraint.U)) + { + //当前同一 列/行 如果容纳 此元素空间将超出 + if (curLineUis.Count > 0) + { + lineUiCollection.Add(curLineUis); + } + + curLineUis = new UVCollection(Orientation, itemSetSize); + curLineUis.Add(child, uvSize, Convert.ToInt32(lengthCount)); + } + else + { + //这里是元素空间足够 + curLineUis.Add(child, uvSize, Convert.ToInt32(lengthCount)); + } + + lineUiCollection.Add(curLineUis); + //下一个可能是换行元素....不管了以后闲得蛋疼再弄吧 + curLineUis = new UVCollection(Orientation, itemSetSize); + } + else + { + uvSize = new UVSize(Orientation, + (isItemWidthSet ? this.ItemWidth : child.DesiredSize.Width), + (isItemHeightSet ? this.ItemHeight : child.DesiredSize.Height)); + + if (MathUtilities.GreaterThan(curLineUis.TotalU + uvSize.U, uvConstraint.U)) + { + //当前同一 列/行 如果容纳 此元素空间将超出 + if (curLineUis.Count > 0) + { + lineUiCollection.Add(curLineUis); + } + + curLineUis = new UVCollection(Orientation, itemSetSize); + curLineUis.Add(child, uvSize); + if (MathUtilities.GreaterThan(uvSize.U, uvConstraint.U)) + { + lineUiCollection.Add(curLineUis); + curLineUis = new UVCollection(Orientation, itemSetSize); + } + } + else + { + //空间足够 + curLineUis.Add(child, uvSize); + } + } + } + + if (curLineUis.Count > 0 && !lineUiCollection.Contains(curLineUis)) + { + lineUiCollection.Add(curLineUis); + } } + #endregion + + bool isFillU = false; + bool isFillV = false; + switch (this.Orientation) + { + case Orientation.Horizontal: + isFillU = this.IsFillHorizontal; + isFillV = this.IsFillVertical; + break; + + case Orientation.Vertical: + isFillU = this.IsFillVertical; + isFillV = this.IsFillHorizontal; + break; + } + + if (lineUiCollection.Count > 0) + { + double accumulatedV = 0; + double adaptULength = 0; + bool isAdaptV = false; + double adaptVLength = 0; + if (isFillU) + { + if (itemSetSize.U > 0) + { + int maxElementCount = lineUiCollection + .Max(uiSet => uiSet.UICollection + .Sum(p => p.Value.ULengthCount)); + adaptULength = (uvConstraint.U - maxElementCount * itemSetSize.U) / maxElementCount; + adaptULength = Math.Max(adaptULength, 0); + } + } + + if (isFillV) + { + if (itemSetSize.V > 0) + { + isAdaptV = true; + adaptVLength = uvConstraint.V / lineUiCollection.Count; + } + } + + bool isHorizontal = (Orientation == Orientation.Horizontal); + foreach (var lineUVCollection in lineUiCollection) + { + double u = 0; + var lineUiEles = lineUVCollection.UICollection.Keys.ToList(); + double linevV = isAdaptV ? adaptVLength : lineUVCollection.LineV; + foreach (var child in lineUiEles) + { + UVLengthSize childSize = lineUVCollection.UICollection[child]; + + double layoutSlotU = childSize.UVSize.U + childSize.ULengthCount * adaptULength; + double layoutSlotV = isAdaptV ? linevV : childSize.UVSize.V; + if (ElasticWrapPanel.GetIsFixToRB(child) == false) + { + child.Arrange(new Rect( + isHorizontal ? u : accumulatedV, + isHorizontal ? accumulatedV : u, + isHorizontal ? layoutSlotU : layoutSlotV, + isHorizontal ? layoutSlotV : layoutSlotU)); + } + else + { + if (itemSetSize.U > 0) + { + //说明同方向有宽度设置,这里尽量按照ItemULength保持 + layoutSlotU = childSize.ULengthCount * itemSetSize.U + + childSize.ULengthCount * adaptULength; + double leaveULength = uvConstraint.U - u; + layoutSlotU = Math.Min(leaveULength, layoutSlotU); + } + + child.Arrange(new Rect( + (isHorizontal ? Math.Max(0, (uvConstraint.U - layoutSlotU)) : accumulatedV), + (isHorizontal ? accumulatedV : Math.Max(0, (uvConstraint.U - layoutSlotU))), + (isHorizontal ? layoutSlotU : layoutSlotV), + (isHorizontal ? layoutSlotV : layoutSlotU))); + } + + u += layoutSlotU; + } + + accumulatedV += linevV; + lineUiEles.Clear(); + } + } + + lineUiCollection.ForEach(col => col.Dispose()); + lineUiCollection.Clear(); return finalSize; } + + #region Protected Methods + + 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; + } + + internal double U; + internal double V; + private Orientation _orientation; + + internal double Width + { + get { return _orientation == Orientation.Horizontal ? U : V; } + set + { + if (_orientation == Orientation.Horizontal) U = value; + else V = value; + } + } + + internal double Height + { + get { return _orientation == Orientation.Horizontal ? V : U; } + set + { + if (_orientation == Orientation.Horizontal) V = value; + else U = value; + } + } + } + + private class UVLengthSize + { + public UVSize UVSize { get; set; } + + public int ULengthCount { get; set; } + + public UVLengthSize(UVSize uvSize, int uLengthCount) + { + this.UVSize = uvSize; + this.ULengthCount = uLengthCount; + } + } + + /// + /// Elements used to store the same row/column + /// + private class UVCollection : IDisposable + { + public Dictionary UICollection { get; } + + private UVSize LineDesireUVSize; + + private UVSize ItemSetSize; + + public UVCollection(Orientation orientation, UVSize itemSetSize) + { + this.UICollection = new Dictionary(); + LineDesireUVSize = new UVSize(orientation); + this.ItemSetSize = itemSetSize; + } + + public double TotalU => LineDesireUVSize.U; + + public double LineV => LineDesireUVSize.V; + + public void Add(Control element, UVSize childSize, int itemULength = 1) + { + if (this.UICollection.ContainsKey(element)) + throw new InvalidOperationException("The element already exists and cannot be added repeatedly."); + + this.UICollection[element] = new UVLengthSize(childSize, itemULength); + LineDesireUVSize.U += childSize.U; + LineDesireUVSize.V = Math.Max(LineDesireUVSize.V, childSize.V); + } + + public int Count => UICollection.Count; + + public void Dispose() + { + UICollection.Clear(); + } + } + + #endregion } \ No newline at end of file From 6b3dc98a93104a600c3ca36393c4522742be7c35 Mon Sep 17 00:00:00 2001 From: Zhang Dian <54255897+zdpcdt@users.noreply.github.com> Date: Tue, 12 Sep 2023 19:37:26 +0800 Subject: [PATCH 03/15] feat: restore MeasureOverride. --- src/Ursa/Controls/ElasticWrapPanel.cs | 144 +++++++++++++------------- 1 file changed, 71 insertions(+), 73 deletions(-) diff --git a/src/Ursa/Controls/ElasticWrapPanel.cs b/src/Ursa/Controls/ElasticWrapPanel.cs index 7d7b3ef..d18fc2a 100644 --- a/src/Ursa/Controls/ElasticWrapPanel.cs +++ b/src/Ursa/Controls/ElasticWrapPanel.cs @@ -65,60 +65,60 @@ public class ElasticWrapPanel : WrapPanel #endregion - protected override Size MeasureOverride(Size availableSize) + protected override Size MeasureOverride(Size constraint) { - //是否元素宽度设置,是否元素高度设置 - bool isItemWidthSet = !double.IsNaN(this.ItemWidth) && this.ItemWidth > 0; - bool isItemHeightSet = !double.IsNaN(this.ItemHeight) && this.ItemHeight > 0; + double itemWidth = ItemWidth; + double itemHeight = ItemHeight; + var orientation = Orientation; + var children = Children; + // 将元素按照水平/垂直排列的方式得出同一行/列所需的空间需求 + var curLineSize = new UVSize(orientation); + // 计算处此 ElasticWrapPanel 所需的空间大小需求结果 + var panelSize = new UVSize(orientation); + // 给定的空间大小测量 UVSize,用于没有 ItemWidth 和 ItemHeight 时候测量元素空间大小 + // FixToRB=True 的元素也使用这个 + var uvConstraint = new UVSize(orientation, constraint.Width, constraint.Height); + bool itemWidthSet = !double.IsNaN(itemWidth); + bool itemHeightSet = !double.IsNaN(itemHeight); - //非FixToRB=True元素使用测量需求空间Size - Size childConstraint = new Size( - (isItemWidthSet ? this.ItemWidth : availableSize.Width), - (isItemHeightSet ? this.ItemHeight : availableSize.Height)); + var childConstraint = new Size( + itemWidthSet ? itemWidth : constraint.Width, + itemHeightSet ? itemHeight : constraint.Height); - //FixToRB=True元素使用测量需求空间Size - Size childFixConstraint = new Size(availableSize.Width, availableSize.Height); - if (Orientation == Orientation.Horizontal && isItemHeightSet) + // FixToRB=True 元素使用测量需求空间 Size + Size childFixConstraint = new Size(constraint.Width, constraint.Height); + switch (orientation) { - childFixConstraint = new Size(availableSize.Width, this.ItemHeight); + case Orientation.Horizontal when itemHeightSet: + childFixConstraint = new Size(constraint.Width, itemHeight); + break; + case Orientation.Vertical when itemWidthSet: + childFixConstraint = new Size(itemWidth, itemHeight); + break; } - if (Orientation == Orientation.Vertical && isItemWidthSet) - { - childFixConstraint = new Size(this.ItemWidth, this.ItemHeight); - } - - //这个给非空间测量大小 - UVSize itemSetSize = new UVSize(this.Orientation, - (isItemWidthSet ? this.ItemWidth : 0), - (isItemHeightSet ? this.ItemHeight : 0)); + UVSize itemSetSize = new UVSize(orientation, + itemWidthSet ? itemWidth : 0, + itemHeightSet ? itemHeight : 0); - //给定的空间大小测量UVSize,用于没有ItemWidth和ItemHeight时候测量元素空间大小, FixToRB=True的元素也使用这个 - UVSize uvConstraint = new UVSize(Orientation, availableSize.Width, availableSize.Height); - //将元素按照水平/垂直排列的方式得出同一行/列所需的空间需求 - UVSize curLineSize = new UVSize(Orientation); - //计算处此ElasticWrapPanel所需的空间大小需求结果 - UVSize desireResultSize = new UVSize(Orientation); - - var children = Children; for (int i = 0, count = children.Count; i < count; i++) { var child = children[i]; - UVSize uvSize; + UVSize sz; if (ElasticWrapPanel.GetIsFixToRB(child)) { //此元素需要设置到固定靠右/底的型为操作,测量元素大小时需要放开 child.Measure(childFixConstraint); - uvSize = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); + sz = new UVSize(orientation, child.DesiredSize.Width, child.DesiredSize.Height); //主要是我对与这个固定住的元素的需求宽度高度按照那个标准有点头疼,干脆放开用最大控件算了 - if (uvSize.U > 0 && itemSetSize.U > 0) + if (sz.U > 0 && itemSetSize.U > 0) { - if (uvSize.U < itemSetSize.U) + if (sz.U < itemSetSize.U) { //保持比例 - uvSize.U = itemSetSize.U; + sz.U = itemSetSize.U; } else { @@ -126,78 +126,76 @@ public class ElasticWrapPanel : WrapPanel //double lengthCount = Math.Ceiling(sz.U / ItemSetSize.U); //sz.U = lengthCount * ItemSetSize.U; //这里防止意外 - uvSize.U = Math.Min(uvSize.U, uvConstraint.U); + sz.U = Math.Min(sz.U, uvConstraint.U); } } - if (uvSize.V > 0 && itemSetSize.V > 0 && uvSize.V < itemSetSize.V) + if (sz.V > 0 && itemSetSize.V > 0 && sz.V < itemSetSize.V) { //设置了垂直方向元素长度,如果此元素空间需求小于,则按照ItemSetSize.V - uvSize.V = itemSetSize.V; + sz.V = itemSetSize.V; } - if (MathUtilities.GreaterThan(curLineSize.U + uvSize.U, uvConstraint.U)) + if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) { //当前同一 列/行 如果容纳 此元素空间将超出 - desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); - desireResultSize.V += curLineSize.V; - - curLineSize = uvSize; + panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.V += curLineSize.V; + curLineSize = sz; //当前元素需要启1个新行 - desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); - desireResultSize.V += curLineSize.V; + panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.V += curLineSize.V; } - else { //这里是元素空间足够 填充式布局 - curLineSize.U += uvSize.U; - curLineSize.V = Math.Max(uvSize.V, curLineSize.V); - desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); - desireResultSize.V += curLineSize.V; + curLineSize.U += sz.U; + curLineSize.V = Math.Max(sz.V, curLineSize.V); + panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.V += curLineSize.V; } //下一个可能是换行元素....用于存放全新1行 - curLineSize = new UVSize(Orientation); + curLineSize = new UVSize(orientation); } else { - //如果设置元素宽度或高度,其高度宽度尽可能按照设置值给定 + // Flow passes its own constraint to children child.Measure(childConstraint); - uvSize = new UVSize(Orientation, - (isItemWidthSet ? this.ItemWidth : child.DesiredSize.Width), - (isItemHeightSet ? this.ItemHeight : child.DesiredSize.Height)); - if (MathUtilities.GreaterThan(curLineSize.U + uvSize.U, uvConstraint.U)) + + // This is the size of the child in UV space + sz = new UVSize(Orientation, + itemWidthSet ? this.ItemWidth : child.DesiredSize.Width, + itemHeightSet ? this.ItemHeight : child.DesiredSize.Height); + + if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) // Need to switch to another line { - //当前同一 列/行 如果容纳 此元素空间将超出 - desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); - desireResultSize.V += curLineSize.V; - curLineSize = uvSize; - if (MathUtilities.GreaterThan(uvSize.U, uvConstraint.U)) + panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.V += curLineSize.V; + curLineSize = sz; + + if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) // The element is wider then the constraint - give it a separate line { - //此元素同Orientation方向长度大于给定约束长度,则当前元素为一行 - desireResultSize.U = Math.Max(uvSize.U, desireResultSize.U); - desireResultSize.V += uvSize.V; - //用于存放全新1行宽度 + panelSize.U = Math.Max(sz.U, panelSize.U); + panelSize.V += sz.V; curLineSize = new UVSize(Orientation); } } - else + else // Continue to accumulate a line { - //当前同一 列/行 元素空间足够,可以容纳当前元素 - curLineSize.U += uvSize.U; - curLineSize.V = Math.Max(uvSize.V, curLineSize.V); + curLineSize.U += sz.U; + curLineSize.V = Math.Max(sz.V, curLineSize.V); } } } - //the last line size, if any should be added - desireResultSize.U = Math.Max(curLineSize.U, desireResultSize.U); - desireResultSize.V += curLineSize.V; + // The last line size, if any should be added + panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.V += curLineSize.V; - //go from UV space to W/H space - return new Size(desireResultSize.Width, desireResultSize.Height); + // Go from UV space to W/H space + return new Size(panelSize.Width, panelSize.Height); } protected override Size ArrangeOverride(Size finalSize) From f727ca852eee18c8161fe62e1fbab1aa284df119 Mon Sep 17 00:00:00 2001 From: Zhang Dian <54255897+zdpcdt@users.noreply.github.com> Date: Tue, 12 Sep 2023 23:51:55 +0800 Subject: [PATCH 04/15] feat: restore ArrangeOverride method. --- src/Ursa/Controls/ElasticWrapPanel.cs | 222 +++++++++++++------------- 1 file changed, 108 insertions(+), 114 deletions(-) diff --git a/src/Ursa/Controls/ElasticWrapPanel.cs b/src/Ursa/Controls/ElasticWrapPanel.cs index d18fc2a..f41c0e3 100644 --- a/src/Ursa/Controls/ElasticWrapPanel.cs +++ b/src/Ursa/Controls/ElasticWrapPanel.cs @@ -102,9 +102,8 @@ public class ElasticWrapPanel : WrapPanel itemWidthSet ? itemWidth : 0, itemHeightSet ? itemHeight : 0); - for (int i = 0, count = children.Count; i < count; i++) + foreach (var child in children) { - var child = children[i]; UVSize sz; if (ElasticWrapPanel.GetIsFixToRB(child)) { @@ -200,138 +199,133 @@ public class ElasticWrapPanel : WrapPanel protected override Size ArrangeOverride(Size finalSize) { - //设否元素宽的设置,是否元素高度设置 - bool isItemWidthSet = !double.IsNaN(this.ItemWidth) && this.ItemWidth > 0; - bool isItemHeightSet = !double.IsNaN(this.ItemHeight) && this.ItemHeight > 0; + //是否元素宽度设置,是否元素高度设置 + bool itemWidthSet = !double.IsNaN(ItemWidth); + bool itemHeightSet = !double.IsNaN(ItemHeight); //这个给非空间测量大小 - UVSize itemSetSize = new UVSize(this.Orientation, - (isItemWidthSet ? this.ItemWidth : 0), - (isItemHeightSet ? this.ItemHeight : 0)); + UVSize itemSetSize = new UVSize(Orientation, + itemWidthSet ? ItemWidth : 0, + itemHeightSet ? ItemHeight : 0); - //给定的空间大小测量UVSize,用于没有ItemWidth和ItemHeight时候测量元素空间大小,FixToRB=True的元素也使用这个 - UVSize uvConstraint = new UVSize(Orientation, finalSize.Width, finalSize.Height); + //给定的空间大小测量 UVSize,用于没有 ItemWidth 和 ItemHeight 时候测量元素空间大小 + //FixToRB=True 的元素也使用这个 + UVSize uvFinalSize = new UVSize(Orientation, finalSize.Width, finalSize.Height); //用于存放同一方向的元素列/行 集合 - List lineUiCollection = new List(); + List lineUVCollection = new List(); #region 得到同一方向元素集合的集合 - //写一个If只是用于减少外层变量,反感的请将if注释 - //if (lineUiCollection != null) + //当前元素集合行/列 + UVCollection curLineUIs = new UVCollection(Orientation, itemSetSize); + + //遍历内部元素 + var children = Children; + foreach (var child in children) { - //当前元素集合行/列 - UVCollection curLineUis = new UVCollection(this.Orientation, itemSetSize); - - //遍历内部元素 - var children = Children; - for (int i = 0, count = children.Count; i < count; i++) + UVSize sz; + if (ElasticWrapPanel.GetIsFixToRB(child)) { - var child = children[i]; - // if (child.Visibility == Visibility.Collapsed) continue; - UVSize uvSize = new UVSize(); - if (ElasticWrapPanel.GetIsFixToRB(child)) + //此元素需要设置到固定靠右/底的型为操作,测量元素大小时需要放开 + sz = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); + double lengthCount = 1; + if (sz.U > 0 && itemSetSize.U > 0) { - //此元素需要设置到固定靠右/底的型为操作,测量元素大小时需要放开 - uvSize = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); - double lengthCount = 1; - if (uvSize.U > 0 && itemSetSize.U > 0) + if (sz.U < itemSetSize.U) { - if (uvSize.U < itemSetSize.U) - { - //保持比例 - uvSize.U = itemSetSize.U; - } - else - { - //设置了同方向中元素的长度,所以这里要按照比例 - lengthCount = Math.Ceiling(uvSize.U / itemSetSize.U); - //sz.U = lengthCount * ItemSetSize.U; - uvSize.U = Math.Min(uvSize.U, uvConstraint.U); - } - } - - if (uvSize.V > 0 && itemSetSize.V > 0 && uvSize.V < itemSetSize.V) - { - //设置了垂直方向元素长度,如果此元素空间需求小于,则按照ItemSetSize.V - uvSize.V = itemSetSize.V; - } - - if (MathUtilities.GreaterThan(curLineUis.TotalU + uvSize.U, uvConstraint.U)) - { - //当前同一 列/行 如果容纳 此元素空间将超出 - if (curLineUis.Count > 0) - { - lineUiCollection.Add(curLineUis); - } - - curLineUis = new UVCollection(Orientation, itemSetSize); - curLineUis.Add(child, uvSize, Convert.ToInt32(lengthCount)); + //保持比例 + sz.U = itemSetSize.U; } else { - //这里是元素空间足够 - curLineUis.Add(child, uvSize, Convert.ToInt32(lengthCount)); + //设置了同方向中元素的长度,所以这里要按照比例 + lengthCount = Math.Ceiling(sz.U / itemSetSize.U); + //sz.U = lengthCount * ItemSetSize.U; + sz.U = Math.Min(sz.U, uvFinalSize.U); + } + } + + if (sz.V > 0 && itemSetSize.V > 0 && sz.V < itemSetSize.V) + { + //设置了垂直方向元素长度,如果此元素空间需求小于,则按照ItemSetSize.V + sz.V = itemSetSize.V; + } + + if (MathUtilities.GreaterThan(curLineUIs.TotalU + sz.U, uvFinalSize.U)) + { + //当前同一 列/行 如果容纳 此元素空间将超出 + if (curLineUIs.Count > 0) + { + lineUVCollection.Add(curLineUIs); } - lineUiCollection.Add(curLineUis); - //下一个可能是换行元素....不管了以后闲得蛋疼再弄吧 - curLineUis = new UVCollection(Orientation, itemSetSize); + curLineUIs = new UVCollection(Orientation, itemSetSize); + curLineUIs.Add(child, sz, Convert.ToInt32(lengthCount)); } else { - uvSize = new UVSize(Orientation, - (isItemWidthSet ? this.ItemWidth : child.DesiredSize.Width), - (isItemHeightSet ? this.ItemHeight : child.DesiredSize.Height)); + //这里是元素空间足够 + curLineUIs.Add(child, sz, Convert.ToInt32(lengthCount)); + } - if (MathUtilities.GreaterThan(curLineUis.TotalU + uvSize.U, uvConstraint.U)) + lineUVCollection.Add(curLineUIs); + //下一个可能是换行元素....不管了以后闲得蛋疼再弄吧 + curLineUIs = new UVCollection(Orientation, itemSetSize); + } + else + { + sz = new UVSize(Orientation, + itemWidthSet ? ItemWidth : child.DesiredSize.Width, + itemHeightSet ? ItemHeight : child.DesiredSize.Height); + + if (MathUtilities.GreaterThan(curLineUIs.TotalU + sz.U, uvFinalSize.U)) // Need to switch to another line + { + //当前同一 列/行 如果容纳 此元素空间将超出 + if (curLineUIs.Count > 0) { - //当前同一 列/行 如果容纳 此元素空间将超出 - if (curLineUis.Count > 0) - { - lineUiCollection.Add(curLineUis); - } - - curLineUis = new UVCollection(Orientation, itemSetSize); - curLineUis.Add(child, uvSize); - if (MathUtilities.GreaterThan(uvSize.U, uvConstraint.U)) - { - lineUiCollection.Add(curLineUis); - curLineUis = new UVCollection(Orientation, itemSetSize); - } + lineUVCollection.Add(curLineUIs); } - else + + curLineUIs = new UVCollection(Orientation, itemSetSize); + curLineUIs.Add(child, sz); + if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) { - //空间足够 - curLineUis.Add(child, uvSize); + lineUVCollection.Add(curLineUIs); + curLineUIs = new UVCollection(Orientation, itemSetSize); } } + else + { + //空间足够 + curLineUIs.Add(child, sz); + } } + } - if (curLineUis.Count > 0 && !lineUiCollection.Contains(curLineUis)) - { - lineUiCollection.Add(curLineUis); - } + if (curLineUIs.Count > 0 && !lineUVCollection.Contains(curLineUIs)) + { + lineUVCollection.Add(curLineUIs); } #endregion bool isFillU = false; bool isFillV = false; - switch (this.Orientation) + switch (Orientation) { case Orientation.Horizontal: - isFillU = this.IsFillHorizontal; - isFillV = this.IsFillVertical; + isFillU = IsFillHorizontal; + isFillV = IsFillVertical; break; case Orientation.Vertical: - isFillU = this.IsFillVertical; - isFillV = this.IsFillHorizontal; + isFillU = IsFillVertical; + isFillV = IsFillHorizontal; break; } - if (lineUiCollection.Count > 0) + if (lineUVCollection.Count > 0) { double accumulatedV = 0; double adaptULength = 0; @@ -341,10 +335,10 @@ public class ElasticWrapPanel : WrapPanel { if (itemSetSize.U > 0) { - int maxElementCount = lineUiCollection + int maxElementCount = lineUVCollection .Max(uiSet => uiSet.UICollection .Sum(p => p.Value.ULengthCount)); - adaptULength = (uvConstraint.U - maxElementCount * itemSetSize.U) / maxElementCount; + adaptULength = (uvFinalSize.U - maxElementCount * itemSetSize.U) / maxElementCount; adaptULength = Math.Max(adaptULength, 0); } } @@ -354,19 +348,19 @@ public class ElasticWrapPanel : WrapPanel if (itemSetSize.V > 0) { isAdaptV = true; - adaptVLength = uvConstraint.V / lineUiCollection.Count; + adaptVLength = uvFinalSize.V / lineUVCollection.Count; } } - bool isHorizontal = (Orientation == Orientation.Horizontal); - foreach (var lineUVCollection in lineUiCollection) + bool isHorizontal = Orientation == Orientation.Horizontal; + foreach (var uvCollection in lineUVCollection) { double u = 0; - var lineUiEles = lineUVCollection.UICollection.Keys.ToList(); - double linevV = isAdaptV ? adaptVLength : lineUVCollection.LineV; - foreach (var child in lineUiEles) + var lineUIEles = uvCollection.UICollection.Keys.ToList(); + double linevV = isAdaptV ? adaptVLength : uvCollection.LineV; + foreach (var child in lineUIEles) { - UVLengthSize childSize = lineUVCollection.UICollection[child]; + UVLengthSize childSize = uvCollection.UICollection[child]; double layoutSlotU = childSize.UVSize.U + childSize.ULengthCount * adaptULength; double layoutSlotV = isAdaptV ? linevV : childSize.UVSize.V; @@ -382,30 +376,30 @@ public class ElasticWrapPanel : WrapPanel { if (itemSetSize.U > 0) { - //说明同方向有宽度设置,这里尽量按照ItemULength保持 + //说明同方向有宽度设置,这里尽量按照 ItemULength 保持 layoutSlotU = childSize.ULengthCount * itemSetSize.U + childSize.ULengthCount * adaptULength; - double leaveULength = uvConstraint.U - u; + double leaveULength = uvFinalSize.U - u; layoutSlotU = Math.Min(leaveULength, layoutSlotU); } child.Arrange(new Rect( - (isHorizontal ? Math.Max(0, (uvConstraint.U - layoutSlotU)) : accumulatedV), - (isHorizontal ? accumulatedV : Math.Max(0, (uvConstraint.U - layoutSlotU))), - (isHorizontal ? layoutSlotU : layoutSlotV), - (isHorizontal ? layoutSlotV : layoutSlotU))); + isHorizontal ? Math.Max(0, uvFinalSize.U - layoutSlotU) : accumulatedV, + isHorizontal ? accumulatedV : Math.Max(0, uvFinalSize.U - layoutSlotU), + isHorizontal ? layoutSlotU : layoutSlotV, + isHorizontal ? layoutSlotV : layoutSlotU)); } u += layoutSlotU; } accumulatedV += linevV; - lineUiEles.Clear(); + lineUIEles.Clear(); } } - lineUiCollection.ForEach(col => col.Dispose()); - lineUiCollection.Clear(); + lineUVCollection.ForEach(col => col.Dispose()); + lineUVCollection.Clear(); return finalSize; } @@ -478,9 +472,9 @@ public class ElasticWrapPanel : WrapPanel public UVCollection(Orientation orientation, UVSize itemSetSize) { - this.UICollection = new Dictionary(); + UICollection = new Dictionary(); LineDesireUVSize = new UVSize(orientation); - this.ItemSetSize = itemSetSize; + ItemSetSize = itemSetSize; } public double TotalU => LineDesireUVSize.U; @@ -489,10 +483,10 @@ public class ElasticWrapPanel : WrapPanel public void Add(Control element, UVSize childSize, int itemULength = 1) { - if (this.UICollection.ContainsKey(element)) + if (UICollection.ContainsKey(element)) throw new InvalidOperationException("The element already exists and cannot be added repeatedly."); - this.UICollection[element] = new UVLengthSize(childSize, itemULength); + UICollection[element] = new UVLengthSize(childSize, itemULength); LineDesireUVSize.U += childSize.U; LineDesireUVSize.V = Math.Max(LineDesireUVSize.V, childSize.V); } From ef4d871bcf8d6ea9dfc82c5f1e5115b94591dc74 Mon Sep 17 00:00:00 2001 From: Zhang Dian <54255897+zdpcdt@users.noreply.github.com> Date: Wed, 13 Sep 2023 00:15:02 +0800 Subject: [PATCH 05/15] feat: extract Math static method. --- src/Ursa/Controls/ElasticWrapPanel.cs | 44 ++++++++++++++------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/Ursa/Controls/ElasticWrapPanel.cs b/src/Ursa/Controls/ElasticWrapPanel.cs index f41c0e3..6195ff4 100644 --- a/src/Ursa/Controls/ElasticWrapPanel.cs +++ b/src/Ursa/Controls/ElasticWrapPanel.cs @@ -3,6 +3,8 @@ using Avalonia.Controls; using Avalonia.Layout; using Avalonia.Utilities; +using static System.Math; + namespace Ursa.Controls; public class ElasticWrapPanel : WrapPanel @@ -122,10 +124,10 @@ public class ElasticWrapPanel : WrapPanel else { //设置了同方向中元素的长度,所以这里要按照比例 - //double lengthCount = Math.Ceiling(sz.U / ItemSetSize.U); + //double lengthCount = Ceiling(sz.U / ItemSetSize.U); //sz.U = lengthCount * ItemSetSize.U; //这里防止意外 - sz.U = Math.Min(sz.U, uvConstraint.U); + sz.U = Min(sz.U, uvConstraint.U); } } @@ -138,20 +140,20 @@ public class ElasticWrapPanel : WrapPanel if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) { //当前同一 列/行 如果容纳 此元素空间将超出 - panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.U = Max(curLineSize.U, panelSize.U); panelSize.V += curLineSize.V; curLineSize = sz; //当前元素需要启1个新行 - panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.U = Max(curLineSize.U, panelSize.U); panelSize.V += curLineSize.V; } else { //这里是元素空间足够 填充式布局 curLineSize.U += sz.U; - curLineSize.V = Math.Max(sz.V, curLineSize.V); - panelSize.U = Math.Max(curLineSize.U, panelSize.U); + curLineSize.V = Max(sz.V, curLineSize.V); + panelSize.U = Max(curLineSize.U, panelSize.U); panelSize.V += curLineSize.V; } @@ -164,33 +166,33 @@ public class ElasticWrapPanel : WrapPanel child.Measure(childConstraint); // This is the size of the child in UV space - sz = new UVSize(Orientation, - itemWidthSet ? this.ItemWidth : child.DesiredSize.Width, - itemHeightSet ? this.ItemHeight : child.DesiredSize.Height); + sz = new UVSize(orientation, + itemWidthSet ? itemWidth : child.DesiredSize.Width, + itemHeightSet ? itemHeight : child.DesiredSize.Height); if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) // Need to switch to another line { - panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.U = Max(curLineSize.U, panelSize.U); panelSize.V += curLineSize.V; curLineSize = sz; if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) // The element is wider then the constraint - give it a separate line { - panelSize.U = Math.Max(sz.U, panelSize.U); + panelSize.U = Max(sz.U, panelSize.U); panelSize.V += sz.V; - curLineSize = new UVSize(Orientation); + curLineSize = new UVSize(orientation); } } else // Continue to accumulate a line { curLineSize.U += sz.U; - curLineSize.V = Math.Max(sz.V, curLineSize.V); + curLineSize.V = Max(sz.V, curLineSize.V); } } } // The last line size, if any should be added - panelSize.U = Math.Max(curLineSize.U, panelSize.U); + panelSize.U = Max(curLineSize.U, panelSize.U); panelSize.V += curLineSize.V; // Go from UV space to W/H space @@ -240,9 +242,9 @@ public class ElasticWrapPanel : WrapPanel else { //设置了同方向中元素的长度,所以这里要按照比例 - lengthCount = Math.Ceiling(sz.U / itemSetSize.U); + lengthCount = Ceiling(sz.U / itemSetSize.U); //sz.U = lengthCount * ItemSetSize.U; - sz.U = Math.Min(sz.U, uvFinalSize.U); + sz.U = Min(sz.U, uvFinalSize.U); } } @@ -339,7 +341,7 @@ public class ElasticWrapPanel : WrapPanel .Max(uiSet => uiSet.UICollection .Sum(p => p.Value.ULengthCount)); adaptULength = (uvFinalSize.U - maxElementCount * itemSetSize.U) / maxElementCount; - adaptULength = Math.Max(adaptULength, 0); + adaptULength = Max(adaptULength, 0); } } @@ -380,12 +382,12 @@ public class ElasticWrapPanel : WrapPanel layoutSlotU = childSize.ULengthCount * itemSetSize.U + childSize.ULengthCount * adaptULength; double leaveULength = uvFinalSize.U - u; - layoutSlotU = Math.Min(leaveULength, layoutSlotU); + layoutSlotU = Min(leaveULength, layoutSlotU); } child.Arrange(new Rect( - isHorizontal ? Math.Max(0, uvFinalSize.U - layoutSlotU) : accumulatedV, - isHorizontal ? accumulatedV : Math.Max(0, uvFinalSize.U - layoutSlotU), + isHorizontal ? Max(0, uvFinalSize.U - layoutSlotU) : accumulatedV, + isHorizontal ? accumulatedV : Max(0, uvFinalSize.U - layoutSlotU), isHorizontal ? layoutSlotU : layoutSlotV, isHorizontal ? layoutSlotV : layoutSlotU)); } @@ -488,7 +490,7 @@ public class ElasticWrapPanel : WrapPanel UICollection[element] = new UVLengthSize(childSize, itemULength); LineDesireUVSize.U += childSize.U; - LineDesireUVSize.V = Math.Max(LineDesireUVSize.V, childSize.V); + LineDesireUVSize.V = Max(LineDesireUVSize.V, childSize.V); } public int Count => UICollection.Count; From 2d15767f00d67337c7de6cc23c344aa70016ce1b Mon Sep 17 00:00:00 2001 From: Zhang Dian <54255897+zdpcdt@users.noreply.github.com> Date: Mon, 18 Sep 2023 13:12:28 +0800 Subject: [PATCH 06/15] feat: demo page. --- .../Pages/ElasticWrapPanelDemo.axaml | 646 +++++++++++++++++- src/Ursa/Controls/ElasticWrapPanel.cs | 6 +- 2 files changed, 645 insertions(+), 7 deletions(-) diff --git a/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml b/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml index cbe4dfc..c41ea21 100644 --- a/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml +++ b/demo/Ursa.Demo/Pages/ElasticWrapPanelDemo.axaml @@ -5,8 +5,646 @@ xmlns:u="https://irihi.tech/ursa" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Ursa.Demo.Pages.ElasticWrapPanelDemo"> - - - - + + + + + + + Vertical + Horizontal + + + + Auto + Disabled + Hidden + Visible + + + + Auto + Disabled + Hidden + Visible + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Top + Center + Bottom + Stretch + + + Left + Center + Right + Stretch + + + + + + + +