mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
temp fix wrap layout
This commit is contained in:
@@ -63,12 +63,12 @@ internal sealed partial class UniformStaggeredLayout : VirtualizingLayout
|
||||
/// <inheritdoc/>
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<WrapItem> 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"profiles": {
|
||||
"Snap.Hutao": {
|
||||
"commandName": "MsixPackage",
|
||||
"nativeDebugging": false,
|
||||
"nativeDebugging": true,
|
||||
"doNotLaunchApp": false,
|
||||
"allowLocalNetworkLoopbackProperty": true
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user