Skip to content

Instantly share code, notes, and snippets.

@Larry57
Last active December 17, 2015 15:19
Show Gist options
  • Save Larry57/5630622 to your computer and use it in GitHub Desktop.
Save Larry57/5630622 to your computer and use it in GitHub Desktop.
Arrange items in a panel like a thumbnails manager
public static void Arrange(Control container, int horizontalGap, int verticalGap, float aspectRatio)
{
var H = container.Height;
var W = container.Width;
var N = container.Controls.OfType<Control>().Count(c => c.Visible);
if (N == 0)
return;
var bestSizedItem = (
// Try n rows
Enumerable.Range(1, N).Select(testRowCount =>
{
var testItemHeight = (H - verticalGap * (testRowCount - 1)) / testRowCount;
return new
{
testColCount = (int)Math.Ceiling((double)N / testRowCount),
testRowCount = testRowCount,
testItemHeight = (int)testItemHeight,
testItemWidth = (int)(testItemHeight * aspectRatio)
};
})
// Try n columns
.Concat(
Enumerable.Range(1, N).Select(testColCount =>
{
var testItemWidth = (W - horizontalGap * (testColCount - 1)) / testColCount;
return new
{
testColCount = testColCount,
testRowCount = (int)Math.Ceiling((double)N / testColCount),
testItemHeight = (int)(testItemWidth / aspectRatio),
testItemWidth = (int)testItemWidth
};
})))
// Remove when it's too big
.Where(item => item.testItemWidth * item.testColCount + horizontalGap * (item.testColCount - 1) <= W &&
item.testItemHeight * item.testRowCount + verticalGap * (item.testRowCount - 1) <= H)
// Get the biggest area
.OrderBy(item => item.testItemHeight * item.testItemWidth)
.LastOrDefault();
Debug.Assert(bestSizedItem != null);
if (bestSizedItem == null)
return;
// Centering
int xCenter = (W - (bestSizedItem.testItemWidth * bestSizedItem.testColCount + bestSizedItem.testColCount * horizontalGap - horizontalGap)) / 2;
int x = xCenter;
int yCenter = (H - (bestSizedItem.testItemHeight * bestSizedItem.testRowCount + bestSizedItem.testRowCount * verticalGap - verticalGap)) / 2;
int y = yCenter;
container.SuspendLayout();
foreach (var control in container.Controls.OfType<Control>().Where(c => c.Visible))
{
control.SetBounds(x, y,
bestSizedItem.testItemWidth,
bestSizedItem.testItemHeight);
x += bestSizedItem.testItemWidth + horizontalGap;
if (x + bestSizedItem.testItemWidth - horizontalGap > W)
{
x = xCenter;
y += bestSizedItem.testItemHeight + verticalGap;
}
}
container.ResumeLayout(false);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment