Browse Source

Implemented UniformGrid. (#1819)

pull/1824/head
jp2masa 8 years ago
committed by Nelson Carrillo
parent
commit
f1e422866a
  1. 161
      src/Avalonia.Controls/Primitives/UniformGrid.cs
  2. 144
      tests/Avalonia.Controls.UnitTests/Primitives/UniformGridTests.cs

161
src/Avalonia.Controls/Primitives/UniformGrid.cs

@ -0,0 +1,161 @@
using System;
namespace Avalonia.Controls.Primitives
{
/// <summary>
/// A <see cref="Panel"/> with uniform column and row sizes.
/// </summary>
public class UniformGrid : Panel
{
/// <summary>
/// Defines the <see cref="Rows"/> property.
/// </summary>
public static readonly StyledProperty<int> RowsProperty =
AvaloniaProperty.Register<UniformGrid, int>(nameof(Rows));
/// <summary>
/// Defines the <see cref="Columns"/> property.
/// </summary>
public static readonly StyledProperty<int> ColumnsProperty =
AvaloniaProperty.Register<UniformGrid, int>(nameof(Columns));
/// <summary>
/// Defines the <see cref="FirstColumn"/> property.
/// </summary>
public static readonly StyledProperty<int> FirstColumnProperty =
AvaloniaProperty.Register<UniformGrid, int>(nameof(FirstColumn));
private int _rows;
private int _columns;
/// <summary>
/// Specifies the row count. If set to 0, row count will be calculated automatically.
/// </summary>
public int Rows
{
get => GetValue(RowsProperty);
set => SetValue(RowsProperty, value);
}
/// <summary>
/// Specifies the column count. If set to 0, column count will be calculated automatically.
/// </summary>
public int Columns
{
get => GetValue(ColumnsProperty);
set => SetValue(ColumnsProperty, value);
}
/// <summary>
/// Specifies, for the first row, the column where the items should start.
/// </summary>
public int FirstColumn
{
get => GetValue(FirstColumnProperty);
set => SetValue(FirstColumnProperty, value);
}
protected override Size MeasureOverride(Size availableSize)
{
UpdateRowsAndColumns();
var maxWidth = 0d;
var maxHeight = 0d;
var childAvailableSize = new Size(availableSize.Width / _columns, availableSize.Height / _rows);
foreach (var child in Children)
{
child.Measure(childAvailableSize);
if (child.DesiredSize.Width > maxWidth)
{
maxWidth = child.DesiredSize.Width;
}
if (child.DesiredSize.Height > maxHeight)
{
maxHeight = child.DesiredSize.Height;
}
}
return new Size(maxWidth * _columns, maxHeight * _rows);
}
protected override Size ArrangeOverride(Size finalSize)
{
var x = FirstColumn;
var y = 0;
var width = finalSize.Width / _columns;
var height = finalSize.Height / _rows;
foreach (var child in Children)
{
if (!child.IsVisible)
{
continue;
}
child.Arrange(new Rect(x * width, y * height, width, height));
x++;
if (x >= _columns)
{
x = 0;
y++;
}
}
return finalSize;
}
private void UpdateRowsAndColumns()
{
_rows = Rows;
_columns = Columns;
if (FirstColumn >= Columns)
{
FirstColumn = 0;
}
var itemCount = FirstColumn;
foreach (var child in Children)
{
if (child.IsVisible)
{
itemCount++;
}
}
if (_rows == 0)
{
if (_columns == 0)
{
_rows = _columns = (int)Math.Ceiling(Math.Sqrt(itemCount));
}
else
{
_rows = Math.DivRem(itemCount, _columns, out int rem);
if (rem != 0)
{
_rows++;
}
}
}
else if (_columns == 0)
{
_columns = Math.DivRem(itemCount, _rows, out int rem);
if (rem != 0)
{
_columns++;
}
}
}
}
}

144
tests/Avalonia.Controls.UnitTests/Primitives/UniformGridTests.cs

@ -0,0 +1,144 @@
using Avalonia.Controls.Primitives;
using Xunit;
namespace Avalonia.Controls.UnitTests.Primitives
{
public class UniformGridTests
{
[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
Assert.Equal(new Size(2 * 80, 2 * 90), 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
Assert.Equal(new Size(2 * 80, 3 * 90), 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
Assert.Equal(new Size(3 * 80, 3 * 90), 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
Assert.Equal(new Size(3 * 80, 2 * 90), 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
Assert.Equal(new Size(2 * 80, 2 * 90), 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));
// 2 * 2 grid
Assert.Equal(new Size(2 * 50, 2 * 70), target.Bounds.Size);
}
}
}
Loading…
Cancel
Save