From cf431719df58263af793ea6443c38f5aa65c197b Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Tue, 21 May 2024 23:14:51 +0800 Subject: [PATCH] temp fix wrap layout --- .../Control/Layout/UniformStaggeredLayout.cs | 4 +- .../Snap.Hutao/Control/Layout/WrapItem.cs | 6 +- .../Snap.Hutao/Control/Layout/WrapLayout.cs | 119 +++++++++--------- .../Control/Layout/WrapLayoutState.cs | 18 +-- .../Snap.Hutao/Properties/launchSettings.json | 2 +- 5 files changed, 80 insertions(+), 69 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Layout/UniformStaggeredLayout.cs b/src/Snap.Hutao/Snap.Hutao/Control/Layout/UniformStaggeredLayout.cs index 6817858d..02c869c1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Layout/UniformStaggeredLayout.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Layout/UniformStaggeredLayout.cs @@ -63,12 +63,12 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout /// protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) { - if (context.ItemCount == 0) + if (context.ItemCount is 0) { return new Size(availableSize.Width, 0); } - if ((context.RealizationRect.Width == 0) && (context.RealizationRect.Height == 0)) + if ((context.RealizationRect.Width is 0) && (context.RealizationRect.Height is 0)) { return new Size(availableSize.Width, 0.0f); } diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapItem.cs b/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapItem.cs index d96e18a8..290afc69 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapItem.cs @@ -8,6 +8,8 @@ namespace Snap.Hutao.Control.Layout; internal sealed class WrapItem { + public static Point EmptyPosition { get; } = new(float.NegativeInfinity, float.NegativeInfinity); + public WrapItem(int index) { Index = index; @@ -15,9 +17,9 @@ internal sealed class WrapItem public int Index { get; } - public Size? Size { get; set; } + public Size Size { get; set; } = Size.Empty; - public Point? Position { get; set; } + public Point Position { get; set; } = EmptyPosition; public UIElement? Element { get; set; } } diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayout.cs b/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayout.cs index d3132d8f..9dd89d75 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayout.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayout.cs @@ -15,13 +15,11 @@ internal sealed partial class WrapLayout : VirtualizingLayout protected override void InitializeForContextCore(VirtualizingLayoutContext context) { context.LayoutState = new WrapLayoutState(context); - base.InitializeForContextCore(context); } protected override void UninitializeForContextCore(VirtualizingLayoutContext context) { context.LayoutState = default; - base.UninitializeForContextCore(context); } protected override void OnItemsChangedCore(VirtualizingLayoutContext context, object source, NotifyCollectionChangedEventArgs args) @@ -60,6 +58,16 @@ internal sealed partial class WrapLayout : VirtualizingLayout protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize) { + if (context.ItemCount is 0) + { + return new Size(availableSize.Width, 0); + } + + if ((context.RealizationRect.Width is 0) && (context.RealizationRect.Height is 0)) + { + return new Size(availableSize.Width, 0.0f); + } + Size spacing = new(HorizontalSpacing, VerticalSpacing); WrapLayoutState state = (WrapLayoutState)context.LayoutState; @@ -68,42 +76,42 @@ internal sealed partial class WrapLayout : VirtualizingLayout { state.ClearPositions(); state.Spacing = spacing; - state.AvailableWidth = availableSize.Height; + state.AvailableWidth = availableSize.Width; } double currentHeight = 0; - Point position = default; + Point itemPosition = default; for (int i = 0; i < context.ItemCount; ++i) { - bool measured = false; + bool itemMeasured = false; WrapItem item = state.GetItemAt(i); - if (item.Size is null) + if (item.Size == Size.Empty) { item.Element = context.GetOrCreateElementAt(i); item.Element.Measure(availableSize); item.Size = item.Element.DesiredSize; - measured = true; + itemMeasured = true; } - Size currentSize = item.Size.Value; + Size itemSize = item.Size; - if (item.Position is null) + if (item.Position == WrapItem.EmptyPosition) { - if (availableSize.Width < position.X + currentSize.Height) + if (availableSize.Width < itemPosition.X + itemSize.Width) { // New Row - position.X = 0; - position.Y += currentHeight + spacing.Height; + itemPosition.X = 0; + itemPosition.Y += currentHeight + spacing.Height; currentHeight = 0; } - item.Position = position; + item.Position = itemPosition; } - position = item.Position.Value; + itemPosition = item.Position; - double vEnd = position.Y + currentSize.Width; - if (vEnd < context.RealizationRect.Top) + double bottom = itemPosition.Y + itemSize.Height; + if (bottom < context.RealizationRect.Top) { // Item is "above" the bounds if (item.Element is not null) @@ -114,7 +122,7 @@ internal sealed partial class WrapLayout : VirtualizingLayout continue; } - else if (position.Y > context.RealizationRect.Bottom) + else if (itemPosition.Y > context.RealizationRect.Bottom) { // Item is "below" the bounds. if (item.Element is not null) @@ -126,34 +134,34 @@ internal sealed partial class WrapLayout : VirtualizingLayout // We don't need to measure anything below the bounds break; } - else if (!measured) + else if (!itemMeasured) { // Always measure elements that are within the bounds item.Element = context.GetOrCreateElementAt(i); item.Element.Measure(availableSize); - currentSize = item.Element.DesiredSize; - if (currentSize != item.Size) + itemSize = item.Element.DesiredSize; + if (itemSize != item.Size) { // this item changed size; we need to recalculate layout for everything after this state.RemoveFromIndex(i + 1); - item.Size = currentSize; + item.Size = itemSize; // did the change make it go into the new row? - if (availableSize.Width < position.X + currentSize.Width) + if (availableSize.Width < itemPosition.X + itemSize.Width) { // New Row - position.X = 0; - position.Y += currentHeight + spacing.Height; + itemPosition.X = 0; + itemPosition.Y += currentHeight + spacing.Height; currentHeight = 0; } - item.Position = position; + item.Position = itemPosition; } } - position.X += currentSize.Width + spacing.Width; - currentHeight = Math.Max(currentSize.Height, currentHeight); + itemPosition.X += itemSize.Width + spacing.Width; + currentHeight = Math.Max(itemSize.Height, currentHeight); } return new Size(double.IsInfinity(availableSize.Width) ? 0 : Math.Ceiling(availableSize.Width), state.GetHeight()); @@ -165,34 +173,9 @@ internal sealed partial class WrapLayout : VirtualizingLayout { WrapLayoutState state = (WrapLayoutState)context.LayoutState; - bool ArrangeItem(WrapItem item) - { - if (item is { Size: null } or { Position: null }) - { - return false; - } - - Size desiredSize = item.Size.Value; - - Point position = item.Position.Value; - - if (context.RealizationRect.Top <= position.Y + desiredSize.Height && position.Y <= context.RealizationRect.Bottom) - { - // place the item - UIElement child = context.GetOrCreateElementAt(item.Index); - child.Arrange(new Rect(position, desiredSize)); - } - else if (position.Y > context.RealizationRect.Bottom) - { - return false; - } - - return true; - } - for (int i = 0; i < context.ItemCount; ++i) { - if (!ArrangeItem(state.GetItemAt(i))) + if (!ArrangeItem(context, state.GetItemAt(i))) { break; } @@ -200,14 +183,38 @@ internal sealed partial class WrapLayout : VirtualizingLayout } return finalSize; + + static bool ArrangeItem(VirtualizingLayoutContext context, WrapItem item) + { + if (item.Size == Size.Empty || item.Position == WrapItem.EmptyPosition) + { + return false; + } + + Size size = item.Size; + Point position = item.Position; + + if (context.RealizationRect.Top <= position.Y + size.Height && position.Y <= context.RealizationRect.Bottom) + { + // place the item + UIElement child = context.GetOrCreateElementAt(item.Index); + child.Arrange(new Rect(position, size)); + } + else if (position.Y > context.RealizationRect.Bottom) + { + return false; + } + + return true; + } } private static void LayoutPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - if (d is WrapLayout wp) + if (d is WrapLayout layout) { - wp.InvalidateMeasure(); - wp.InvalidateArrange(); + layout.InvalidateMeasure(); + layout.InvalidateArrange(); } } } diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayoutState.cs b/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayoutState.cs index 395a6e0e..f84fab8c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayoutState.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Layout/WrapLayoutState.cs @@ -1,7 +1,6 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System.Runtime.InteropServices; using Windows.Foundation; @@ -26,7 +25,10 @@ internal sealed class WrapLayoutState public WrapItem GetItemAt(int index) { - ArgumentOutOfRangeException.ThrowIfNegative(index); + if (index < 0) + { + throw new IndexOutOfRangeException(); + } if (index <= (items.Count - 1)) { @@ -80,23 +82,24 @@ internal sealed class WrapLayoutState Point? lastPosition = default; double maxHeight = 0; + Span itemSpan = CollectionsMarshal.AsSpan(items); for (int i = items.Count - 1; i >= 0; --i) { - WrapItem item = items[i]; + ref readonly WrapItem item = ref itemSpan[i]; - if (item.Position is null || item.Size is null) + if (item.Position == WrapItem.EmptyPosition || item.Size == Size.Empty) { continue; } - if (lastPosition is not null && lastPosition.Value.Y > item.Position.Value.Y) + if (lastPosition is not null && lastPosition.Value.Y > item.Position.Y) { // This is a row above the last item. break; } lastPosition = item.Position; - maxHeight = Math.Max(maxHeight, item.Size.Value.Height); + maxHeight = Math.Max(maxHeight, item.Size.Height); } return lastPosition?.Y + maxHeight ?? 0; @@ -104,7 +107,6 @@ internal sealed class WrapLayoutState public void RecycleElementAt(int index) { - UIElement element = context.GetOrCreateElementAt(index); - context.RecycleElement(element); + context.RecycleElement(context.GetOrCreateElementAt(index)); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Properties/launchSettings.json b/src/Snap.Hutao/Snap.Hutao/Properties/launchSettings.json index a5fb2a14..36a6b395 100644 --- a/src/Snap.Hutao/Snap.Hutao/Properties/launchSettings.json +++ b/src/Snap.Hutao/Snap.Hutao/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "Snap.Hutao": { "commandName": "MsixPackage", - "nativeDebugging": false, + "nativeDebugging": true, "doNotLaunchApp": false, "allowLocalNetworkLoopbackProperty": true },