diff --git a/QuestPDF.Examples/TableExamples.cs b/QuestPDF.Examples/TableExamples.cs index 46c8d63..493e8be 100644 --- a/QuestPDF.Examples/TableExamples.cs +++ b/QuestPDF.Examples/TableExamples.cs @@ -49,6 +49,39 @@ namespace QuestPDF.Examples }); } + [Test] + public void PagingSupport() + { + RenderingTest + .Create() + .ProducePdf() + .PageSize(420, 220) + .ShowResults() + .Render(container => + { + container + .Padding(10) + .MinimalBox() + .Border(1) + .Table(table => + { + table.ColumnsDefinition(columns => + { + columns.RelativeColumn(); + columns.RelativeColumn(); + columns.RelativeColumn(); + columns.RelativeColumn(); + }); + + // by using custom 'Element' method, we can reuse visual configuration + table.Cell().Element(Block).Text(Placeholders.Label()); + table.Cell().Element(Block).Text(Placeholders.Label()); + table.Cell().Element(Block).Text(Placeholders.Paragraph()); + table.Cell().Element(Block).Text(Placeholders.Label()); + }); + }); + } + [Test] public void DefaultCellStyle() { @@ -217,7 +250,7 @@ namespace QuestPDF.Examples RenderingTest .Create() .ProduceImages() - .PageSize(220, 220) + .PageSize(220, 170) .ShowResults() .Render(container => { @@ -380,7 +413,7 @@ namespace QuestPDF.Examples .EnableCaching() .EnableDebugging(false) .ShowResults() - .Render(container => GeneratePerformanceStructure(container, 1000)); + .Render(container => GeneratePerformanceStructure(container, 250)); } public static void GeneratePerformanceStructure(IContainer container, int repeats) @@ -456,8 +489,10 @@ namespace QuestPDF.Examples return container .Border(1) .Background(Colors.Grey.Lighten3) + .ShowOnce() .MinWidth(50) .MinHeight(50) + .Padding(10) .AlignCenter() .AlignMiddle(); } diff --git a/QuestPDF.UnitTests/RowTests.cs b/QuestPDF.UnitTests/RowTests.cs index fc1db47..de74a76 100644 --- a/QuestPDF.UnitTests/RowTests.cs +++ b/QuestPDF.UnitTests/RowTests.cs @@ -102,6 +102,7 @@ namespace QuestPDF.UnitTests .DrawElement(new Size(400, 300)) .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150)) .ExpectChildDraw("left", new Size(250, 300)) + .ExpectChildMeasure("right", new Size(150, 300), SpacePlan.FullRender(150, 200)) .ExpectCanvasTranslate(250, 0) .ExpectChildDraw("right", new Size(150, 300)) .ExpectCanvasTranslate(-250, 0) diff --git a/QuestPDF/Elements/Row.cs b/QuestPDF/Elements/Row.cs index 045bd49..a315c84 100644 --- a/QuestPDF/Elements/Row.cs +++ b/QuestPDF/Elements/Row.cs @@ -57,17 +57,11 @@ namespace QuestPDF.Elements if (leftMeasurement.Type == SpacePlanType.Wrap) return SpacePlan.Wrap(); - if (leftMeasurement.Type == SpacePlanType.FullRender) - IsLeftRendered = true; - var rightMeasurement = Right.Measure(new Size(availableSpace.Width - leftMeasurement.Width, availableSpace.Height)); if (rightMeasurement.Type == SpacePlanType.Wrap) return SpacePlan.Wrap(); - - if (leftMeasurement.Type == SpacePlanType.FullRender) - IsRightRendered = true; - + var totalWidth = leftMeasurement.Width + rightMeasurement.Width; var totalHeight = Math.Max(leftMeasurement.Height, rightMeasurement.Height); @@ -82,14 +76,23 @@ namespace QuestPDF.Elements internal override void Draw(Size availableSpace) { - var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height)); - var leftWidth = leftMeasurement.Width; + var leftSpace = new Size(availableSpace.Width, availableSpace.Height); + var leftMeasurement = Left.Measure(leftSpace); + + if (leftMeasurement.Type == SpacePlanType.FullRender) + IsLeftRendered = true; - Left.Draw(new Size(leftWidth, availableSpace.Height)); + Left.Draw(new Size(leftMeasurement.Width, availableSpace.Height)); + + var rightSpace = new Size(availableSpace.Width - leftMeasurement.Width, availableSpace.Height); + var rightMeasurement = Right.Measure(rightSpace); - Canvas.Translate(new Position(leftWidth, 0)); - Right.Draw(new Size(availableSpace.Width - leftWidth, availableSpace.Height)); - Canvas.Translate(new Position(-leftWidth, 0)); + if (rightMeasurement.Type == SpacePlanType.FullRender) + IsRightRendered = true; + + Canvas.Translate(new Position(leftMeasurement.Width, 0)); + Right.Draw(rightSpace); + Canvas.Translate(new Position(-leftMeasurement.Width, 0)); } } diff --git a/QuestPDF/Elements/Table/Table.cs b/QuestPDF/Elements/Table/Table.cs index 1362f40..f508576 100644 --- a/QuestPDF/Elements/Table/Table.cs +++ b/QuestPDF/Elements/Table/Table.cs @@ -15,15 +15,19 @@ namespace QuestPDF.Elements.Table public List Cells { get; set; } = new List(); public bool ExtendLastCellsToTableBottom { get; set; } - // cache for efficient cell finding - // index of first array - number of row - // nested array - collection of all cells starting at given row - private TableCell[][] OrderedCells { get; set; } - private int StartingRowsCount { get; set; } private int RowsCount { get; set; } private int CurrentRow { get; set; } + internal override void Initialize(IPageContext pageContext, ICanvas canvas) + { + StartingRowsCount = Cells.Select(x => x.Row).DefaultIfEmpty(0).Max(); + RowsCount = Cells.Select(x => x.Row + x.RowSpan - 1).DefaultIfEmpty(0).Max(); + Cells = Cells.OrderBy(x => x.Row).ThenBy(x => x.Column).ToList(); + + base.Initialize(pageContext, canvas); + } + internal override IEnumerable GetChildren() { return Cells; @@ -31,24 +35,6 @@ namespace QuestPDF.Elements.Table public void ResetState() { - if (StartingRowsCount == default) - StartingRowsCount = Cells.Select(x => x.Row).DefaultIfEmpty(0).Max(); - - if (RowsCount == default) - RowsCount = Cells.Select(x => x.Row + x.RowSpan - 1).DefaultIfEmpty(0).Max(); - - if (OrderedCells == default) - { - var groups = Cells - .GroupBy(x => x.Row) - .ToDictionary(x => x.Key, x => x.OrderBy(y => y.Column).ToArray()); - - OrderedCells = Enumerable - .Range(0, RowsCount + 1) - .Select(x => groups.TryGetValue(x, out var output) ? output : Array.Empty()) - .ToArray(); - } - Cells.ForEach(x => x.IsRendered = false); CurrentRow = 1; } @@ -85,6 +71,9 @@ namespace QuestPDF.Elements.Table { if (command.Measurement.Type == SpacePlanType.FullRender) command.Cell.IsRendered = true; + + if (command.Measurement.Type == SpacePlanType.Wrap) + continue; Canvas.Translate(command.Offset); command.Cell.Draw(command.Size); @@ -103,7 +92,7 @@ namespace QuestPDF.Elements.Table { return commands .GroupBy(x => x.Cell.Row) - .Where(x => x.All(y => y.Measurement.Type == SpacePlanType.FullRender)) + .Where(x => x.All(y => y.Cell.IsRendered || y.Measurement.Type == SpacePlanType.FullRender)) .Select(x => x.Key) .DefaultIfEmpty(0) .Max(); @@ -152,16 +141,12 @@ namespace QuestPDF.Elements.Table ICollection GetRenderingCommands() { var rowBottomOffsets = new DynamicDictionary(); + var commands = new List(); - var cellsToTry = Enumerable - .Range(CurrentRow, RowsCount - CurrentRow + 1) - .SelectMany(x => OrderedCells[x]); - + var cellsToTry = Cells.Where(x => x.Row + x.RowSpan - 1 >= CurrentRow); var currentRow = CurrentRow; var maxRenderingRow = RowsCount; - var commands = new List(); - foreach (var cell in cellsToTry) { // update position of previous row @@ -181,10 +166,7 @@ namespace QuestPDF.Elements.Table // cell visibility optimizations if (cell.Row > maxRenderingRow) break; - - if (cell.IsRendered) - continue; - + // calculate cell position / size var topOffset = rowBottomOffsets[cell.Row - 1]; diff --git a/QuestPDF/Helpers/Placeholders.cs b/QuestPDF/Helpers/Placeholders.cs index 6a6d5b5..5fa1e64 100644 --- a/QuestPDF/Helpers/Placeholders.cs +++ b/QuestPDF/Helpers/Placeholders.cs @@ -7,7 +7,7 @@ namespace QuestPDF.Helpers { public static class Placeholders { - public static readonly Random Random = new Random(3); // 3 + public static readonly Random Random = new(); #region Word Cache diff --git a/QuestPDF/Infrastructure/Element.cs b/QuestPDF/Infrastructure/Element.cs index a964be1..bbb63ba 100644 --- a/QuestPDF/Infrastructure/Element.cs +++ b/QuestPDF/Infrastructure/Element.cs @@ -15,7 +15,7 @@ namespace QuestPDF.Infrastructure yield break; } - internal void Initialize(IPageContext pageContext, ICanvas canvas) + internal virtual void Initialize(IPageContext pageContext, ICanvas canvas) { PageContext = pageContext; Canvas = canvas; diff --git a/QuestPDF/QuestPDF.csproj b/QuestPDF/QuestPDF.csproj index 107d1e6..3e8929d 100644 --- a/QuestPDF/QuestPDF.csproj +++ b/QuestPDF/QuestPDF.csproj @@ -4,7 +4,7 @@ MarcinZiabek CodeFlint QuestPDF - 2022.1.0-beta4 + 2022.1.0-beta5 QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API. $([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt")) 9