feat: add TrailingWrapWidth.
This commit is contained in:
@@ -6,18 +6,15 @@ using Irihi.Avalonia.Shared.Helpers;
|
|||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
public class WrapPanelWithTrailingItem: Panel
|
public class WrapPanelWithTrailingItem : Panel
|
||||||
{
|
{
|
||||||
public static readonly StyledProperty<Layoutable?> TrailingItemProperty = AvaloniaProperty.Register<WrapPanelWithTrailingItem, Layoutable?>(
|
public static readonly StyledProperty<Layoutable?> TrailingItemProperty =
|
||||||
nameof(TrailingItem));
|
AvaloniaProperty.Register<WrapPanelWithTrailingItem, Layoutable?>(
|
||||||
|
nameof(TrailingItem));
|
||||||
|
|
||||||
public Layoutable? TrailingItem
|
public static readonly StyledProperty<double> TrailingWrapWidthProperty =
|
||||||
{
|
AvaloniaProperty.Register<WrapPanelWithTrailingItem, double>(
|
||||||
get => GetValue(TrailingItemProperty);
|
nameof(TrailingWrapWidth));
|
||||||
set => SetValue(TrailingItemProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static WrapPanelWithTrailingItem()
|
static WrapPanelWithTrailingItem()
|
||||||
{
|
{
|
||||||
@@ -25,52 +22,55 @@ public class WrapPanelWithTrailingItem: Panel
|
|||||||
AffectsArrange<WrapPanelWithTrailingItem>(TrailingItemProperty);
|
AffectsArrange<WrapPanelWithTrailingItem>(TrailingItemProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Layoutable? TrailingItem
|
||||||
|
{
|
||||||
|
get => GetValue(TrailingItemProperty);
|
||||||
|
set => SetValue(TrailingItemProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double TrailingWrapWidth
|
||||||
|
{
|
||||||
|
get => GetValue(TrailingWrapWidthProperty);
|
||||||
|
set => SetValue(TrailingWrapWidthProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||||
{
|
{
|
||||||
base.OnPropertyChanged(change);
|
base.OnPropertyChanged(change);
|
||||||
if (change.Property == TrailingItemProperty)
|
if (change.Property == TrailingItemProperty)
|
||||||
{
|
{
|
||||||
if(change.GetOldValue<Layoutable?>() is { } oldValue)
|
if (change.GetOldValue<Layoutable?>() is { } oldValue)
|
||||||
{
|
{
|
||||||
VisualChildren.Remove(oldValue);
|
VisualChildren.Remove(oldValue);
|
||||||
if (!IsItemsHost)
|
if (!IsItemsHost) LogicalChildren.Remove(oldValue);
|
||||||
{
|
|
||||||
LogicalChildren.Remove(oldValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(change.GetNewValue<Layoutable?>() is {} newValue)
|
|
||||||
|
if (change.GetNewValue<Layoutable?>() is { } newValue)
|
||||||
{
|
{
|
||||||
VisualChildren.Add(newValue);
|
VisualChildren.Add(newValue);
|
||||||
if (!IsItemsHost)
|
if (!IsItemsHost) LogicalChildren.Add(newValue);
|
||||||
{
|
|
||||||
LogicalChildren.Add(newValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WrapPanel p = new WrapPanel();
|
WrapPanel p = new WrapPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.ChildrenChanged(sender, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
{
|
{
|
||||||
double currentLineX = 0;
|
double currentLineX = 0;
|
||||||
double currentLineHeight = 0;
|
double currentLineHeight = 0;
|
||||||
double totalHeight = 0;
|
double totalHeight = 0;
|
||||||
|
|
||||||
var children = Children;
|
var children = Children;
|
||||||
foreach (var child in children)
|
foreach (var child in children)
|
||||||
{
|
{
|
||||||
child.Measure(availableSize);
|
child.Measure(availableSize);
|
||||||
double deltaX = availableSize.Width - currentLineX;
|
var deltaX = availableSize.Width - currentLineX;
|
||||||
// Width is enough to place next child
|
// Width is enough to place next child
|
||||||
if (MathHelpers.GreaterThan(deltaX, child.DesiredSize.Width))
|
if (MathHelpers.GreaterThan(deltaX, child.DesiredSize.Width))
|
||||||
{
|
{
|
||||||
currentLineX+=child.DesiredSize.Width;
|
currentLineX += child.DesiredSize.Width;
|
||||||
currentLineHeight = Math.Max(currentLineHeight, child.DesiredSize.Height);
|
currentLineHeight = Math.Max(currentLineHeight, child.DesiredSize.Height);
|
||||||
}
|
}
|
||||||
// Width is not enough to place next child
|
// Width is not enough to place next child
|
||||||
@@ -88,11 +88,11 @@ public class WrapPanelWithTrailingItem: Panel
|
|||||||
var last = TrailingItem;
|
var last = TrailingItem;
|
||||||
if (last is null) return new Size(availableSize.Width, totalHeight);
|
if (last is null) return new Size(availableSize.Width, totalHeight);
|
||||||
last.Measure(availableSize);
|
last.Measure(availableSize);
|
||||||
double lastDeltaX = availableSize.Width - currentLineX;
|
var lastDeltaX = availableSize.Width - currentLineX;
|
||||||
// If width is not enough, add a new line, and recalculate total height
|
// If width is not enough, add a new line, and recalculate total height
|
||||||
if (lastDeltaX < 30)
|
if (lastDeltaX < TrailingWrapWidth)
|
||||||
{
|
{
|
||||||
totalHeight+=currentLineHeight;
|
totalHeight += currentLineHeight;
|
||||||
totalHeight += last.DesiredSize.Height;
|
totalHeight += last.DesiredSize.Height;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -103,23 +103,24 @@ public class WrapPanelWithTrailingItem: Panel
|
|||||||
|
|
||||||
return new Size(availableSize.Width, totalHeight);
|
return new Size(availableSize.Width, totalHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Size ArrangeOverride(Size finalSize)
|
protected override Size ArrangeOverride(Size finalSize)
|
||||||
{
|
{
|
||||||
double currentLineX = 0;
|
double currentLineX = 0;
|
||||||
double currentLineHeight = 0;
|
double currentLineHeight = 0;
|
||||||
double totalHeight = 0;
|
double totalHeight = 0;
|
||||||
var children = Children;
|
var children = Children;
|
||||||
for (int i = 0; i < children.Count; i++)
|
|
||||||
|
foreach (var child in children)
|
||||||
{
|
{
|
||||||
var child = children[i];
|
|
||||||
double deltaX = finalSize.Width - currentLineX;
|
double deltaX = finalSize.Width - currentLineX;
|
||||||
// Width is enough to place next child
|
// Width is enough to place next child
|
||||||
if (MathHelpers.GreaterThan(deltaX, child.DesiredSize.Width))
|
if (MathHelpers.GreaterThan(deltaX, child.DesiredSize.Width))
|
||||||
{
|
{
|
||||||
child.Arrange(new Rect(currentLineX, totalHeight, child.DesiredSize.Width, Math.Max(child.DesiredSize.Height, currentLineHeight)));
|
child.Arrange(new Rect(currentLineX, totalHeight, child.DesiredSize.Width,
|
||||||
currentLineX += child.DesiredSize.Width;
|
Math.Max(child.DesiredSize.Height, currentLineHeight)));
|
||||||
currentLineHeight = Math.Max(currentLineHeight, child.DesiredSize.Height);
|
currentLineX += child.Bounds.Width;
|
||||||
|
currentLineHeight = Math.Max(currentLineHeight, child.Bounds.Height);
|
||||||
}
|
}
|
||||||
// Width is not enough to place next child
|
// Width is not enough to place next child
|
||||||
// reset currentLineX and currentLineHeight
|
// reset currentLineX and currentLineHeight
|
||||||
@@ -128,17 +129,18 @@ public class WrapPanelWithTrailingItem: Panel
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
totalHeight += currentLineHeight;
|
totalHeight += currentLineHeight;
|
||||||
child.Arrange(new Rect(0, totalHeight, Math.Min(child.DesiredSize.Width, finalSize.Width), child.DesiredSize.Height));
|
child.Arrange(new Rect(0, totalHeight, Math.Min(child.DesiredSize.Width, finalSize.Width),
|
||||||
currentLineX = child.DesiredSize.Width;
|
child.DesiredSize.Height));
|
||||||
currentLineHeight = child.DesiredSize.Height;
|
currentLineX = child.Bounds.Width;
|
||||||
|
currentLineHeight = child.Bounds.Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var last = TrailingItem;
|
var last = TrailingItem;
|
||||||
if (last is null) return new Size(finalSize.Width, totalHeight);
|
if (last is null) return new Size(finalSize.Width, totalHeight);
|
||||||
double lastDeltaX = finalSize.Width - currentLineX;
|
var lastDeltaX = finalSize.Width - currentLineX;
|
||||||
// If width is not enough, add a new line, and recalculate total height
|
// If width is not enough, add a new line, and recalculate total height
|
||||||
if (lastDeltaX < 30)
|
if (lastDeltaX < TrailingWrapWidth)
|
||||||
{
|
{
|
||||||
totalHeight += currentLineHeight;
|
totalHeight += currentLineHeight;
|
||||||
last.Arrange(new Rect(0, totalHeight, finalSize.Width, last.DesiredSize.Height));
|
last.Arrange(new Rect(0, totalHeight, finalSize.Width, last.DesiredSize.Height));
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace HeadlessTest.Ursa.Controls.PanelTests;
|
|||||||
|
|
||||||
public class WrapPanelWithTrailingItemTests
|
public class WrapPanelWithTrailingItemTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[AvaloniaFact]
|
||||||
public void Visual_Children_Correct()
|
public void Visual_Children_Correct()
|
||||||
{
|
{
|
||||||
var panel = new WrapPanelWithTrailingItem();
|
var panel = new WrapPanelWithTrailingItem();
|
||||||
@@ -57,7 +57,7 @@ public class WrapPanelWithTrailingItemTests
|
|||||||
Assert.Equal(trailing2, visualChildren[2]);
|
Assert.Equal(trailing2, visualChildren[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[AvaloniaFact]
|
||||||
// Items Appears in Logical Children because IsItemsHost is false for individual Panels
|
// Items Appears in Logical Children because IsItemsHost is false for individual Panels
|
||||||
public void Logical_Children_Correct()
|
public void Logical_Children_Correct()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user