Skip to content

Commit d2792b5

Browse files
committed
Add dynamic column width support
1 parent 9fd41ef commit d2792b5

File tree

4 files changed

+164
-18
lines changed

4 files changed

+164
-18
lines changed

Source/FossPDF.Examples/EnsureSpaceExample.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,63 @@ public void EnsureSpaceWith()
4949
});
5050
});
5151
}
52+
53+
54+
[Test]
55+
public void Test()
56+
{
57+
Document.Create(x =>
58+
{
59+
x.Page(y =>
60+
{
61+
y.Content().Table(t =>
62+
{
63+
t.ColumnsDefinition(c =>
64+
{
65+
c.ConstantColumn(50, Unit.Centimetre, true, true);
66+
c.ConstantColumn(50, Unit.Centimetre, true, true);
67+
c.ConstantColumn(50, Unit.Centimetre, true, false);
68+
});
69+
70+
71+
IContainer DefaultCellStyle(IContainer container, string backgroundColor, bool alignCenter = false)
72+
{
73+
container = container
74+
.Border(1)
75+
.BorderColor(Colors.Grey.Lighten1)
76+
.Background(backgroundColor)
77+
.PaddingVertical(3)
78+
.PaddingHorizontal(3);
79+
80+
if (alignCenter)
81+
{
82+
container = container
83+
.AlignCenter()
84+
.AlignMiddle();
85+
}
86+
87+
return container;
88+
}
89+
90+
IContainer CellStyle(IContainer container) => DefaultCellStyle(container, Colors.White).ShowOnce();
91+
IContainer HeaderCellStyle(IContainer container) => DefaultCellStyle(container, Colors.Grey.Lighten3);
92+
93+
t.Header(x =>
94+
{
95+
x.Cell().Element(HeaderCellStyle).Text("Spalte 1");
96+
x.Cell().Element(HeaderCellStyle).Text("Spalte 2");
97+
x.Cell().Element(HeaderCellStyle).Text("Spalte 3");
98+
});
99+
100+
for (int i = 0; i < 10; i++)
101+
{
102+
t.Cell().Element(CellStyle).Text("111111111");
103+
t.Cell().Element(CellStyle).Text("2222222222222222222222");
104+
t.Cell().Element(CellStyle).Text("3");
105+
}
106+
});
107+
});
108+
}).GeneratePdf("/home/helmut/Downloads/test.pdf");
109+
}
52110
}
53111
}

Source/FossPDF/Elements/Table/Table.cs

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
using System;
2-
using System.Collections.Concurrent;
32
using System.Collections.Generic;
4-
using System.Diagnostics;
53
using System.Linq;
64
using FossPDF.Drawing;
7-
using FossPDF.Fluent;
85
using FossPDF.Infrastructure;
96

107
namespace FossPDF.Elements.Table
@@ -15,6 +12,10 @@ internal class Table : Element, IStateResettable, IContentDirectionAware
1512

1613
public List<TableColumnDefinition> Columns { get; set; } = new();
1714
public List<TableCell> Cells { get; set; } = new();
15+
public List<TableCell> AllCells { get; set; } = new();
16+
public Dictionary<int, float> ColumnsWidth { get; set; } = new();
17+
public Action<Dictionary<int, float>> AfterUpdateColumnsWidth { get; set; }
18+
1819
public bool ExtendLastCellsToTableBottom { get; set; }
1920

2021
private bool CacheInitialized { get; set; }
@@ -149,6 +150,15 @@ private int FindLastRenderedRow(ICollection<TableCellRenderingCommand> commands)
149150

150151
private void UpdateColumnsWidth(float availableWidth)
151152
{
153+
if (ColumnsWidth.Any())
154+
{
155+
foreach (var column in Columns)
156+
{
157+
column.Width = ColumnsWidth[Columns.IndexOf(column)];
158+
}
159+
return;
160+
}
161+
152162
var constantWidth = Columns.Sum(x => x.ConstantSize);
153163
var relativeWidth = Columns.Sum(x => x.RelativeSize);
154164

@@ -158,6 +168,64 @@ private void UpdateColumnsWidth(float availableWidth)
158168
{
159169
column.Width = column.ConstantSize + column.RelativeSize * widthPerRelativeUnit;
160170
}
171+
172+
var cells = AllCells.Where(c => c is { ColumnSpan: 1, RowSpan: 1 });
173+
174+
foreach (var column in Columns.Where(c => c.AllowShrink))
175+
{
176+
var index = Columns.IndexOf(column);
177+
var cellsInColumn = cells.Where(c => c.Column == index + 1);
178+
if (cellsInColumn.Any())
179+
{
180+
ColumnsWidth.Add(index, cellsInColumn.Max(c => c.Measure(Size.Max).Width));
181+
column.Width = Math.Min(column.Width, ColumnsWidth[index]);
182+
}
183+
}
184+
185+
var remainingWidth = availableWidth - Columns.Sum(c => c.Width);
186+
while (remainingWidth > 0)
187+
{
188+
var columnsThatGrow = Columns.Where(c => c.AllowGrow).ToList();
189+
var growStep = remainingWidth / columnsThatGrow.Count;
190+
var anyColumnHasGrown = false;
191+
foreach (var column in columnsThatGrow)
192+
{
193+
var index = Columns.IndexOf(column);
194+
var cellsInColumn = cells.Where(c => c.Column == index + 1);
195+
if (!ColumnsWidth.ContainsKey(index))
196+
{
197+
ColumnsWidth.Add(index, cellsInColumn.Max(c => c.Measure(Size.Max).Width));
198+
}
199+
var newWidth = Math.Min(column.Width + growStep, ColumnsWidth[index]);
200+
if (newWidth > column.Width)
201+
{
202+
anyColumnHasGrown = true;
203+
}
204+
column.Width = newWidth;
205+
remainingWidth = availableWidth - Columns.Sum(c => c.Width);
206+
if (remainingWidth <= 0)
207+
{
208+
break;
209+
}
210+
}
211+
if (!anyColumnHasGrown)
212+
{
213+
break;
214+
}
215+
}
216+
217+
if (remainingWidth > 0)
218+
{
219+
Columns.Last().Width += remainingWidth;
220+
}
221+
222+
foreach (var column in Columns)
223+
{
224+
// Add missing columns, that don't auto size.
225+
ColumnsWidth[Columns.IndexOf(column)] = column.Width;
226+
}
227+
228+
AfterUpdateColumnsWidth?.Invoke(ColumnsWidth);
161229
}
162230

163231
private ICollection<TableCellRenderingCommand> PlanLayout(Size availableSpace)
@@ -309,4 +377,4 @@ float GetCellWidth(TableCell cell)
309377
}
310378
}
311379
}
312-
}
380+
}

Source/FossPDF/Elements/Table/TableColumnDefinition.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@ internal class TableColumnDefinition
77

88
internal float Width { get; set; }
99

10-
public TableColumnDefinition(float constantSize, float relativeSize)
10+
public bool AllowShrink { get; set; }
11+
public bool AllowGrow { get; set; }
12+
13+
public TableColumnDefinition(float constantSize, float relativeSize, bool allowShrink, bool allowGrow)
1114
{
1215
ConstantSize = constantSize;
1316
RelativeSize = relativeSize;
17+
AllowShrink = allowShrink;
18+
AllowGrow = allowGrow;
1419
}
1520
}
16-
}
21+
}

Source/FossPDF/Fluent/TableExtensions.cs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
using System;
2-
using System.Collections;
32
using System.Collections.Generic;
4-
using System.Diagnostics;
53
using System.Linq;
64
using FossPDF.Drawing.Exceptions;
75
using FossPDF.Elements;
@@ -14,19 +12,19 @@ public class TableColumnsDefinitionDescriptor
1412
{
1513
internal List<TableColumnDefinition> Columns { get; } = new();
1614

17-
public void ConstantColumn(float width, Unit unit = Unit.Point)
15+
public void ConstantColumn(float width, Unit unit = Unit.Point, bool allowShrink = false, bool allowGrow = false)
1816
{
19-
ComplexColumn(constantWidth: width.ToPoints(unit));
17+
ComplexColumn(allowShrink, allowGrow, constantWidth: width.ToPoints(unit));
2018
}
2119

22-
public void RelativeColumn(float width = 1)
20+
public void RelativeColumn(float width = 1, bool allowShrink = false, bool allowGrow = false)
2321
{
24-
ComplexColumn(relativeWidth: width);
22+
ComplexColumn(allowShrink, allowGrow, relativeWidth: width);
2523
}
26-
27-
private void ComplexColumn(float constantWidth = 0, float relativeWidth = 0)
24+
25+
private void ComplexColumn(bool allowShrink, bool allowGrow, float constantWidth = 0, float relativeWidth = 0)
2826
{
29-
var columnDefinition = new TableColumnDefinition(constantWidth, relativeWidth);
27+
var columnDefinition = new TableColumnDefinition(constantWidth, relativeWidth, allowShrink, allowGrow);
3028
Columns.Add(columnDefinition);
3129
}
3230
}
@@ -50,8 +48,6 @@ public ITableCellContainer Cell()
5048

5149
public class TableDescriptor
5250
{
53-
internal List<TableColumnDefinition> Columns { get; private set; }
54-
5551
private Table HeaderTable { get; } = new();
5652
private Table ContentTable { get; } = new();
5753
private Table FooterTable { get; } = new();
@@ -94,6 +90,25 @@ internal IElement CreateElement()
9490
{
9591
var container = new Container();
9692

93+
List<TableCell> allTableCells = new();
94+
var tables = new List<Table>() { HeaderTable, ContentTable, FooterTable };
95+
foreach (var table in tables)
96+
{
97+
allTableCells.AddRange(table.Cells);
98+
table.AfterUpdateColumnsWidth += (columnsWidth) =>
99+
{
100+
foreach (var table in tables)
101+
{
102+
table.ColumnsWidth = columnsWidth;
103+
}
104+
};
105+
}
106+
107+
foreach (var table in tables)
108+
{
109+
table.AllCells = allTableCells;
110+
}
111+
97112
ConfigureTable(HeaderTable);
98113
ConfigureTable(ContentTable);
99114
ConfigureTable(FooterTable);
@@ -159,4 +174,4 @@ public static ITableCellContainer RowSpan(this ITableCellContainer tableCellCont
159174
return tableCellContainer.TableCell(x => x.RowSpan = (int)value);
160175
}
161176
}
162-
}
177+
}

0 commit comments

Comments
 (0)