csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
380 lines
14 KiB
380 lines
14 KiB
using System;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.UnitTests;
|
|
using Xunit;
|
|
|
|
namespace Avalonia.Controls.UnitTests.Primitives
|
|
{
|
|
public class UniformGridTests : ScopedTestBase
|
|
{
|
|
[Fact]
|
|
public void Grid_Columns_Equals_Rows_For_Auto_Columns_And_Rows()
|
|
{
|
|
var target = new UniformGrid
|
|
{
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 80, Height = 90 }
|
|
}
|
|
};
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// 2 * 2 grid => each cell: 80 x 90
|
|
// Final size => (2 * 80) x (2 * 90) = 160 x 180
|
|
Assert.Equal(new Size(160, 180), target.Bounds.Size);
|
|
}
|
|
|
|
[Fact]
|
|
public void Grid_Expands_Vertically_For_Columns_With_Auto_Rows()
|
|
{
|
|
var target = new UniformGrid
|
|
{
|
|
Columns = 2,
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 80, Height = 90 },
|
|
new Border { Width = 20, Height = 30 },
|
|
new Border { Width = 40, Height = 60 }
|
|
}
|
|
};
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// 2 * 3 grid => each cell: 80 x 90
|
|
// Final size => (2 * 80) x (3 * 90) = 160 x 270
|
|
Assert.Equal(new Size(160, 270), target.Bounds.Size);
|
|
}
|
|
|
|
[Fact]
|
|
public void Grid_Extends_For_Columns_And_First_Column_With_Auto_Rows()
|
|
{
|
|
var target = new UniformGrid
|
|
{
|
|
Columns = 3,
|
|
FirstColumn = 2,
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 80, Height = 90 },
|
|
new Border { Width = 20, Height = 30 },
|
|
new Border { Width = 40, Height = 60 }
|
|
}
|
|
};
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// 3 * 3 grid => each cell: 80 x 90
|
|
// Final size => (3 * 80) x (3 * 90) = 240 x 270
|
|
Assert.Equal(new Size(240, 270), target.Bounds.Size);
|
|
}
|
|
|
|
[Fact]
|
|
public void Grid_Expands_Horizontally_For_Rows_With_Auto_Columns()
|
|
{
|
|
var target = new UniformGrid
|
|
{
|
|
Rows = 2,
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 80, Height = 90 },
|
|
new Border { Width = 20, Height = 30 },
|
|
new Border { Width = 40, Height = 60 }
|
|
}
|
|
};
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// 3 * 2 grid => each cell: 80 x 90
|
|
// Final size => (3 * 80) x (2 * 90) = 240 x 180
|
|
Assert.Equal(new Size(240, 180), target.Bounds.Size);
|
|
}
|
|
|
|
[Fact]
|
|
public void Grid_Size_Is_Limited_By_Rows_And_Columns()
|
|
{
|
|
var target = new UniformGrid
|
|
{
|
|
Columns = 2,
|
|
Rows = 2,
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 80, Height = 90 },
|
|
new Border { Width = 20, Height = 30 },
|
|
new Border { Width = 40, Height = 60 }
|
|
}
|
|
};
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// 2 * 2 grid => each cell: 80 x 90
|
|
// Final size => (2 * 80) x (2 * 90) = 160 x 180
|
|
Assert.Equal(new Size(160, 180), target.Bounds.Size);
|
|
}
|
|
|
|
[Fact]
|
|
public void Not_Visible_Children_Are_Ignored()
|
|
{
|
|
var target = new UniformGrid
|
|
{
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 80, Height = 90, IsVisible = false },
|
|
new Border { Width = 20, Height = 30 },
|
|
new Border { Width = 40, Height = 60 }
|
|
}
|
|
};
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// Visible children: 4
|
|
// Auto => 2 x 2 grid => each cell: 50 x 70
|
|
// Final size => (2 * 50) x (2 * 70) = 100 x 140
|
|
Assert.Equal(new Size(100, 140), target.Bounds.Size);
|
|
}
|
|
|
|
//
|
|
// New tests to cover RowSpacing and ColumnSpacing
|
|
//
|
|
|
|
[Fact]
|
|
public void Grid_Respects_ColumnSpacing_For_Auto_Columns_And_Rows()
|
|
{
|
|
// We have 3 visible children and no fixed Rows/Columns => 2x2 grid
|
|
// Largest child is 80 x 90. ColumnSpacing = 10, RowSpacing = 0
|
|
var target = new UniformGrid
|
|
{
|
|
ColumnSpacing = 10,
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 80, Height = 90 }
|
|
}
|
|
};
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// Without spacing => width = 2*80 = 160, height = 2*90 = 180
|
|
// With columnSpacing=10 => total width = 2*80 + 1*10 = 170
|
|
// RowSpacing=0 => total height = 180
|
|
Assert.Equal(new Size(170, 180), target.Bounds.Size);
|
|
}
|
|
|
|
[Fact]
|
|
public void Grid_Respects_RowSpacing_For_Auto_Columns_And_Rows()
|
|
{
|
|
// 3 visible children => 2x2 grid again
|
|
// Largest child is 80 x 90. RowSpacing = 15, ColumnSpacing = 0
|
|
var target = new UniformGrid
|
|
{
|
|
RowSpacing = 15,
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 80, Height = 90 }
|
|
}
|
|
};
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// Without spacing => width = 160, height = 180
|
|
// With rowSpacing=15 => total height = 2*90 + 1*15 = 195
|
|
// ColumnSpacing=0 => total width = 160
|
|
Assert.Equal(new Size(160, 195), target.Bounds.Size);
|
|
}
|
|
|
|
[Fact]
|
|
public void Grid_Respects_Both_Row_And_Column_Spacing_For_Fixed_Grid()
|
|
{
|
|
// 4 visible children => 2 rows x 2 columns, each child is 50x70 or 80x90
|
|
// We'll fix the Grid to 2x2 so the largest child dictates the cell size: 80x90
|
|
// RowSpacing=10, ColumnSpacing=5
|
|
var target = new UniformGrid
|
|
{
|
|
Rows = 2,
|
|
Columns = 2,
|
|
RowSpacing = 10,
|
|
ColumnSpacing = 5,
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 80, Height = 90 },
|
|
new Border { Width = 20, Height = 30 },
|
|
}
|
|
};
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// Each cell = 80 x 90
|
|
// Final width = (2 * 80) + (1 * 5) = 160 + 5 = 165
|
|
// Final height = (2 * 90) + (1 * 10) = 180 + 10 = 190
|
|
Assert.Equal(new Size(165, 190), target.Bounds.Size);
|
|
}
|
|
|
|
[Fact]
|
|
public void Grid_Respects_Spacing_When_Invisible_Child_Exists()
|
|
{
|
|
// 3 *visible* children => auto => 2x2 grid
|
|
// Largest child is 80 x 90.
|
|
// Add spacing so we can confirm it doesn't add extra columns/rows for invisible child.
|
|
var target = new UniformGrid
|
|
{
|
|
RowSpacing = 5,
|
|
ColumnSpacing = 5,
|
|
Children =
|
|
{
|
|
new Border { Width = 50, Height = 70 },
|
|
new Border { Width = 80, Height = 90, IsVisible = false },
|
|
new Border { Width = 30, Height = 50 },
|
|
new Border { Width = 40, Height = 60 }
|
|
}
|
|
};
|
|
|
|
// Visible children: 3 => auto => sqrt(3) => 2x2
|
|
// Largest visible child is 50x70 or 30x50 or 40x60 => the biggest is 50x70
|
|
// Actually, let's ensure we have a child bigger than that:
|
|
// (So let's modify the 40x60 to something bigger than 50x70, e.g. 80x90 for clarity)
|
|
// We'll do that in the collection above if needed, but let's keep as is for example.
|
|
|
|
target.Measure(Size.Infinity);
|
|
target.Arrange(new Rect(target.DesiredSize));
|
|
|
|
// The largest visible child is 50x70. So each cell is 50x70.
|
|
// For a 2x2 grid with 3 visible children:
|
|
// - total width = (2 * 50) + (1 * 5) = 100 + 5 = 105
|
|
// - total height = (2 * 70) + (1 * 5) = 140 + 5 = 145
|
|
Assert.Equal(new Size(105, 145), target.Bounds.Size);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Exposes MeasureOverride for testing inherited classes
|
|
/// </summary>
|
|
public class UniformGridExposeMeasureOverride : UniformGrid
|
|
{
|
|
public new Size MeasureOverride(Size availableSize)
|
|
{
|
|
return base.MeasureOverride(availableSize);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Measure_WithRowsAndColumnsZeroAndNonZeroSpacing_ProducesZeroDesiredSize()
|
|
{
|
|
// MeasureOverride() is called by Layoutable.MeasureCore() and it ensures that
|
|
// the desired size is never negative. but in case of inherited classes MeasureOverride() may return negative values.
|
|
var target = new UniformGridExposeMeasureOverride
|
|
{
|
|
Rows = 0,
|
|
Columns = 0,
|
|
RowSpacing = 10,
|
|
ColumnSpacing = 20
|
|
};
|
|
|
|
var availableSize = new Size(100, 100);
|
|
|
|
var desiredSize = target.MeasureOverride(availableSize);
|
|
|
|
// Fail case:
|
|
// Because _rows and _columns are 0, the calculation becomes:
|
|
// totalWidth = maxWidth * 0 + ColumnSpacing * (0 - 1) = -ColumnSpacing
|
|
// totalHeight = maxHeight * 0 + RowSpacing * (0 - 1) = -RowSpacing
|
|
// Expected: (0, 0)
|
|
Assert.Equal(0, desiredSize.Width);
|
|
Assert.Equal(0, desiredSize.Height);
|
|
|
|
}
|
|
|
|
[Fact]
|
|
public void Arrange_Does_Not_Throw_InvalidOperationException_When_Row_Spacing_Takes_All_Available_Height()
|
|
{
|
|
// Minimum required height = 20 (2 row gaps size 10)
|
|
// Provide height of 19 so that row gaps take all available space
|
|
// thus, available height for children may be negative.
|
|
// In that case, UniformGrid should arrange its children with rects of height 0.
|
|
var target = new UniformGrid
|
|
{
|
|
Columns = 1,
|
|
RowSpacing = 10,
|
|
Children =
|
|
{
|
|
new Border(),
|
|
new Border(),
|
|
new Border()
|
|
}
|
|
};
|
|
|
|
var availableSize = new Size(100, 19);
|
|
|
|
target.Measure(Size.Infinity);
|
|
|
|
// Fail case:
|
|
// Invalid operation will be thrown if any child rect contains a negative dimension
|
|
try
|
|
{
|
|
target.Arrange(new Rect(availableSize));
|
|
}
|
|
catch (InvalidOperationException exception)
|
|
{
|
|
Assert.Fail("Arrange threw InvalidOperationException: " + exception.Message);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Arrange_Does_Not_Throw_InvalidOperationException_When_Column_Spacing_Takes_All_Available_Width()
|
|
{
|
|
// Minimum required width = 20 (2 row gaps size 10)
|
|
// Provide width of 19 so that column gaps take all available space
|
|
// thus, available width for children may be negative.
|
|
// In that case, UniformGrid should arrange its children with rects of width 0.
|
|
var target = new UniformGrid
|
|
{
|
|
Rows = 1,
|
|
ColumnSpacing = 10,
|
|
Children =
|
|
{
|
|
new Border(),
|
|
new Border(),
|
|
new Border()
|
|
}
|
|
};
|
|
|
|
var availableSize = new Size(19, 100);
|
|
|
|
target.Measure(Size.Infinity);
|
|
|
|
// Fail case:
|
|
// Invalid operation will be thrown if any child rect contains a negative dimension
|
|
try
|
|
{
|
|
target.Arrange(new Rect(availableSize));
|
|
}
|
|
catch (InvalidOperationException exception)
|
|
{
|
|
Assert.Fail("Arrange threw InvalidOperationException: " + exception.Message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|