Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamic column width support #867

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 71 additions & 0 deletions Source/QuestPDF/Elements/Table/Table.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ internal sealed class Table : Element, IStateResettable, IContentDirectionAware

public List<TableColumnDefinition> Columns { get; set; } = new();
public List<TableCell> Cells { get; set; } = new();
public List<TableCell> AllCells { get; set; } = new();
public Dictionary<int, float> ColumnsWidth { get; set; } = new();
public Action<Dictionary<int, float>> AfterUpdateColumnsWidth { get; set; }

public bool ExtendLastCellsToTableBottom { get; set; }

private bool CacheInitialized { get; set; }
Expand Down Expand Up @@ -146,6 +150,15 @@ private int CalculateCurrentRow(ICollection<TableCellRenderingCommand> commands)

private void UpdateColumnsWidth(float availableWidth)
{
if (ColumnsWidth.Any())
{
foreach (var column in Columns)
{
column.Width = ColumnsWidth[Columns.IndexOf(column)];
}
return;
}

var constantWidth = Columns.Sum(x => x.ConstantSize);
var relativeWidth = Columns.Sum(x => x.RelativeSize);

Expand All @@ -155,6 +168,64 @@ private void UpdateColumnsWidth(float availableWidth)
{
column.Width = column.ConstantSize + column.RelativeSize * widthPerRelativeUnit;
}

var cells = AllCells.Where(c => c is { ColumnSpan: 1, RowSpan: 1 });

foreach (var column in Columns.Where(c => c.AllowShrink))
{
var index = Columns.IndexOf(column);
var cellsInColumn = cells.Where(c => c.Column == index + 1);
if (cellsInColumn.Any())
{
ColumnsWidth.Add(index, cellsInColumn.Max(c => c.Measure(Size.Max).Width));
column.Width = Math.Min(column.Width, ColumnsWidth[index]);
}
}

var remainingWidth = availableWidth - Columns.Sum(c => c.Width);
while (remainingWidth > 0)
{
var columnsThatGrow = Columns.Where(c => c.AllowGrow).ToList();
var growStep = remainingWidth / columnsThatGrow.Count;
var anyColumnHasGrown = false;
foreach (var column in columnsThatGrow)
{
var index = Columns.IndexOf(column);
var cellsInColumn = cells.Where(c => c.Column == index + 1);
if (!ColumnsWidth.ContainsKey(index))
{
ColumnsWidth.Add(index, cellsInColumn.Max(c => c.Measure(Size.Max).Width));
}
var newWidth = Math.Min(column.Width + growStep, ColumnsWidth[index]);
if (newWidth > column.Width)
{
anyColumnHasGrown = true;
}
column.Width = newWidth;
remainingWidth = availableWidth - Columns.Sum(c => c.Width);
if (remainingWidth <= 0)
{
break;
}
}
if (!anyColumnHasGrown)
{
break;
}
}

if (remainingWidth > 0)
{
Columns.Last().Width += remainingWidth;
}

foreach (var column in Columns)
{
// Add missing columns, that don't auto size.
ColumnsWidth[Columns.IndexOf(column)] = column.Width;
}

AfterUpdateColumnsWidth?.Invoke(ColumnsWidth);
}

private ICollection<TableCellRenderingCommand> PlanLayout(Size availableSpace)
Expand Down
7 changes: 6 additions & 1 deletion Source/QuestPDF/Elements/Table/TableColumnDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ internal sealed class TableColumnDefinition

internal float Width { get; set; }

public TableColumnDefinition(float constantSize, float relativeSize)
public bool AllowShrink { get; set; }
public bool AllowGrow { get; set; }

public TableColumnDefinition(float constantSize, float relativeSize, bool allowShrink, bool allowGrow)
{
ConstantSize = constantSize;
RelativeSize = relativeSize;
AllowShrink = allowShrink;
AllowGrow = allowGrow;
}
}
}
33 changes: 26 additions & 7 deletions Source/QuestPDF/Fluent/TableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public class TableColumnsDefinitionDescriptor
/// Defines a column of constant size that occupies the specified horizontal space.
/// </summary>
/// <returns>The container of the newly created column.</returns>
public void ConstantColumn(float width, Unit unit = Unit.Point)
public void ConstantColumn(float width, Unit unit = Unit.Point, bool allowShrink = false, bool allowGrow = false)
{
ComplexColumn(constantWidth: width.ToPoints(unit));
ComplexColumn(allowShrink, allowGrow, constantWidth: width.ToPoints(unit));
}

/// <summary>
Expand All @@ -29,14 +29,14 @@ public void ConstantColumn(float width, Unit unit = Unit.Point)
/// For a table 100 points wide with three columns: a relative size of 1, a relative size of 5, and a constant size of 10 points, they will span 15 points, 75 points, and 10 points respectively.
/// </example>
/// <returns>The container for the newly defined column.</returns>
public void RelativeColumn(float width = 1)
public void RelativeColumn(float width = 1, bool allowShrink = false, bool allowGrow = false)
{
ComplexColumn(relativeWidth: width);
ComplexColumn(allowShrink, allowGrow, relativeWidth: width);
}
private void ComplexColumn(float constantWidth = 0, float relativeWidth = 0)

private void ComplexColumn(bool allowShrink, bool allowGrow, float constantWidth = 0, float relativeWidth = 0)
{
var columnDefinition = new TableColumnDefinition(constantWidth, relativeWidth);
var columnDefinition = new TableColumnDefinition(constantWidth, relativeWidth, allowShrink, allowGrow);
Columns.Add(columnDefinition);
}
}
Expand Down Expand Up @@ -135,6 +135,25 @@ internal IElement CreateElement()
{
var container = new Container();

List<TableCell> allTableCells = new();
var tables = new List<Table>() { HeaderTable, ContentTable, FooterTable };
foreach (var table in tables)
{
allTableCells.AddRange(table.Cells);
table.AfterUpdateColumnsWidth += (columnsWidth) =>
{
foreach (var table in tables)
{
table.ColumnsWidth = columnsWidth;
}
};
}

foreach (var table in tables)
{
table.AllCells = allTableCells;
}

ConfigureTable(HeaderTable);
ConfigureTable(ContentTable);
ConfigureTable(FooterTable);
Expand Down