2018-05-24 01:12:18 +03:00
|
|
|
// Licensed to the .NET Foundation under one or more agreements.
|
|
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
|
|
// See the LICENSE file in the project root for more information.
|
2018-04-07 06:59:40 +03:00
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using Windows.UI.Xaml;
|
|
|
|
using Windows.UI.Xaml.Controls;
|
|
|
|
|
2021-01-08 22:06:10 +03:00
|
|
|
namespace Microsoft.Toolkit.Uwp.UI.Controls
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// The UniformGrid control presents information within a Grid with even spacing.
|
|
|
|
/// </summary>
|
|
|
|
public partial class UniformGrid : Grid
|
|
|
|
{
|
|
|
|
// Provides the next spot in the boolean array with a 'false' value.
|
2021-02-14 11:32:05 +03:00
|
|
|
#pragma warning disable SA1009 // Closing parenthesis must be followed by a space.
|
2018-04-12 03:04:05 +03:00
|
|
|
internal static IEnumerable<(int row, int column)> GetFreeSpot(TakenSpotsReferenceHolder arrayref, int firstcolumn, bool topdown)
|
2021-02-14 11:32:05 +03:00
|
|
|
#pragma warning restore SA1009 // Closing parenthesis must be followed by a space.
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
2018-04-12 00:06:17 +03:00
|
|
|
if (topdown)
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
2020-08-21 00:45:38 +03:00
|
|
|
var rows = arrayref.Height;
|
2018-04-12 09:10:55 +03:00
|
|
|
|
2018-04-12 00:06:17 +03:00
|
|
|
// Layout spots from Top-Bottom, Left-Right (right-left handled automatically by Grid with Flow-Direction).
|
|
|
|
// Effectively transpose the Grid Layout.
|
2020-08-21 00:45:38 +03:00
|
|
|
for (int c = 0; c < arrayref.Width; c++)
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
2018-04-12 09:10:55 +03:00
|
|
|
int start = (c == 0 && firstcolumn > 0 && firstcolumn < rows) ? firstcolumn : 0;
|
|
|
|
for (int r = start; r < rows; r++)
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
2020-08-21 00:45:38 +03:00
|
|
|
if (!arrayref[r, c])
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
|
|
|
yield return (r, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-08-21 00:45:38 +03:00
|
|
|
var columns = arrayref.Width;
|
2018-04-12 09:10:55 +03:00
|
|
|
|
2018-04-12 00:06:17 +03:00
|
|
|
// Layout spots as normal from Left-Right.
|
|
|
|
// (right-left handled automatically by Grid with Flow-Direction
|
|
|
|
// during its layout, internal model is always left-right).
|
2020-08-21 00:45:38 +03:00
|
|
|
for (int r = 0; r < arrayref.Height; r++)
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
2018-04-12 09:10:55 +03:00
|
|
|
int start = (r == 0 && firstcolumn > 0 && firstcolumn < columns) ? firstcolumn : 0;
|
|
|
|
for (int c = start; c < columns; c++)
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
2020-08-21 00:45:38 +03:00
|
|
|
if (!arrayref[r, c])
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
|
|
|
yield return (r, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Based on the number of visible children,
|
|
|
|
// returns the dimensions of the
|
|
|
|
// grid we need to hold all elements.
|
2021-02-14 11:32:05 +03:00
|
|
|
#pragma warning disable SA1008 // Opening parenthesis must be spaced correctly
|
2018-05-03 23:00:05 +03:00
|
|
|
internal static (int rows, int columns) GetDimensions(FrameworkElement[] visible, int rows, int cols, int firstColumn)
|
2021-02-14 11:32:05 +03:00
|
|
|
#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly
|
2018-04-07 06:59:40 +03:00
|
|
|
{
|
|
|
|
// If a dimension isn't specified, we need to figure out the other one (or both).
|
|
|
|
if (rows == 0 || cols == 0)
|
|
|
|
{
|
|
|
|
// Calculate the size & area of all objects in the grid to know how much space we need.
|
2018-04-11 07:26:19 +03:00
|
|
|
var count = Math.Max(1, visible.Sum(item => GetRowSpan(item) * GetColumnSpan(item)));
|
2018-04-07 06:59:40 +03:00
|
|
|
|
|
|
|
if (rows == 0)
|
|
|
|
{
|
|
|
|
if (cols > 0)
|
|
|
|
{
|
2018-04-12 09:10:55 +03:00
|
|
|
// Bound check
|
|
|
|
var first = (firstColumn >= cols || firstColumn < 0) ? 0 : firstColumn;
|
2018-04-07 06:59:40 +03:00
|
|
|
|
|
|
|
// If we have columns but no rows, calculate rows based on column offset and number of children.
|
|
|
|
rows = (count + first + (cols - 1)) / cols;
|
|
|
|
return (rows, cols);
|
|
|
|
}
|
2018-04-12 09:10:55 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Otherwise, determine square layout if both are zero.
|
|
|
|
var size = (int)Math.Ceiling(Math.Sqrt(count));
|
2018-04-07 06:59:40 +03:00
|
|
|
|
2018-04-12 09:10:55 +03:00
|
|
|
// Figure out if firstColumn is in bounds
|
|
|
|
var first = (firstColumn >= size || firstColumn < 0) ? 0 : firstColumn;
|
2018-04-08 08:11:23 +03:00
|
|
|
|
2018-04-12 09:10:55 +03:00
|
|
|
rows = (int)Math.Ceiling(Math.Sqrt(count + first));
|
|
|
|
return (rows, rows);
|
|
|
|
}
|
2018-04-07 06:59:40 +03:00
|
|
|
}
|
|
|
|
else if (cols == 0)
|
|
|
|
{
|
|
|
|
// If we have rows and no columns, then calculate columns needed based on rows
|
|
|
|
cols = (count + (rows - 1)) / rows;
|
|
|
|
|
|
|
|
// Now that we know a rough size of our shape, see if the FirstColumn effects that:
|
2018-04-12 09:10:55 +03:00
|
|
|
var first = (firstColumn >= cols || firstColumn < 0) ? 0 : firstColumn;
|
2018-04-07 06:59:40 +03:00
|
|
|
|
|
|
|
cols = (count + first + (rows - 1)) / rows;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rows, cols);
|
|
|
|
}
|
2018-04-10 09:29:16 +03:00
|
|
|
|
|
|
|
// Used to interleave specified row dimensions with automatic rows added to use
|
|
|
|
// underlying Grid layout for main arrange of UniformGrid.
|
|
|
|
internal void SetupRowDefinitions(int rows)
|
|
|
|
{
|
2018-05-03 01:11:07 +03:00
|
|
|
// Mark initial definitions so we don't erase them.
|
2018-04-10 09:29:16 +03:00
|
|
|
foreach (var rd in RowDefinitions)
|
|
|
|
{
|
|
|
|
if (GetAutoLayout(rd) == null)
|
|
|
|
{
|
|
|
|
SetAutoLayout(rd, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove non-autolayout rows we've added and then add them in the right spots.
|
|
|
|
if (rows != RowDefinitions.Count)
|
|
|
|
{
|
|
|
|
for (int r = RowDefinitions.Count - 1; r >= 0; r--)
|
|
|
|
{
|
|
|
|
if (GetAutoLayout(RowDefinitions[r]) == true)
|
|
|
|
{
|
|
|
|
RowDefinitions.RemoveAt(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-03 01:11:07 +03:00
|
|
|
for (int r = this.RowDefinitions.Count; r < rows; r++)
|
2018-04-10 09:29:16 +03:00
|
|
|
{
|
2018-05-03 01:11:07 +03:00
|
|
|
var rd = new RowDefinition();
|
|
|
|
SetAutoLayout(rd, true);
|
|
|
|
this.RowDefinitions.Insert(r, rd);
|
2018-04-10 09:29:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used to interleave specified column dimensions with automatic columns added to use
|
|
|
|
// underlying Grid layout for main arrange of UniformGrid.
|
|
|
|
internal void SetupColumnDefinitions(int columns)
|
|
|
|
{
|
2018-05-03 01:11:07 +03:00
|
|
|
// Mark initial definitions so we don't erase them.
|
2018-04-10 09:29:16 +03:00
|
|
|
foreach (var cd in ColumnDefinitions)
|
|
|
|
{
|
|
|
|
if (GetAutoLayout(cd) == null)
|
|
|
|
{
|
|
|
|
SetAutoLayout(cd, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove non-autolayout columns we've added and then add them in the right spots.
|
|
|
|
if (columns != ColumnDefinitions.Count)
|
|
|
|
{
|
|
|
|
for (int c = ColumnDefinitions.Count - 1; c >= 0; c--)
|
|
|
|
{
|
|
|
|
if (GetAutoLayout(ColumnDefinitions[c]) == true)
|
|
|
|
{
|
|
|
|
this.ColumnDefinitions.RemoveAt(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-03 01:11:07 +03:00
|
|
|
for (int c = ColumnDefinitions.Count; c < columns; c++)
|
2018-04-10 09:29:16 +03:00
|
|
|
{
|
2018-05-03 01:11:07 +03:00
|
|
|
var cd = new ColumnDefinition();
|
|
|
|
SetAutoLayout(cd, true);
|
|
|
|
ColumnDefinitions.Insert(c, cd);
|
2018-04-10 09:29:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-07 06:59:40 +03:00
|
|
|
}
|
2021-02-14 11:32:05 +03:00
|
|
|
}
|