Kaynağa Gözat

Row: fixed paging behavior, Table: improved paging behavior for already rendered elements

Marcin Ziąbek 4 yıl önce
ebeveyn
işleme
763fdfac0f

+ 37 - 2
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]
         [Test]
         public void DefaultCellStyle()
         public void DefaultCellStyle()
         {
         {
@@ -217,7 +250,7 @@ namespace QuestPDF.Examples
             RenderingTest
             RenderingTest
                 .Create()
                 .Create()
                 .ProduceImages()
                 .ProduceImages()
-                .PageSize(220, 220)
+                .PageSize(220, 170)
                 .ShowResults()
                 .ShowResults()
                 .Render(container =>
                 .Render(container =>
                 {
                 {
@@ -380,7 +413,7 @@ namespace QuestPDF.Examples
                 .EnableCaching()
                 .EnableCaching()
                 .EnableDebugging(false)
                 .EnableDebugging(false)
                 .ShowResults()
                 .ShowResults()
-                .Render(container => GeneratePerformanceStructure(container, 1000));
+                .Render(container => GeneratePerformanceStructure(container, 250));
         }
         }
         
         
         public static void GeneratePerformanceStructure(IContainer container, int repeats)
         public static void GeneratePerformanceStructure(IContainer container, int repeats)
@@ -456,8 +489,10 @@ namespace QuestPDF.Examples
             return container
             return container
                 .Border(1)
                 .Border(1)
                 .Background(Colors.Grey.Lighten3)
                 .Background(Colors.Grey.Lighten3)
+                .ShowOnce()
                 .MinWidth(50)
                 .MinWidth(50)
                 .MinHeight(50)
                 .MinHeight(50)
+                .Padding(10)
                 .AlignCenter()
                 .AlignCenter()
                 .AlignMiddle();
                 .AlignMiddle();
         }
         }

+ 1 - 0
QuestPDF.UnitTests/RowTests.cs

@@ -102,6 +102,7 @@ namespace QuestPDF.UnitTests
                 .DrawElement(new Size(400, 300))
                 .DrawElement(new Size(400, 300))
                 .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150))
                 .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150))
                 .ExpectChildDraw("left", new Size(250, 300))
                 .ExpectChildDraw("left", new Size(250, 300))
+                .ExpectChildMeasure("right", new Size(150, 300), SpacePlan.FullRender(150, 200))
                 .ExpectCanvasTranslate(250, 0)
                 .ExpectCanvasTranslate(250, 0)
                 .ExpectChildDraw("right", new Size(150, 300))
                 .ExpectChildDraw("right", new Size(150, 300))
                 .ExpectCanvasTranslate(-250, 0)
                 .ExpectCanvasTranslate(-250, 0)

+ 16 - 13
QuestPDF/Elements/Row.cs

@@ -57,17 +57,11 @@ namespace QuestPDF.Elements
             if (leftMeasurement.Type == SpacePlanType.Wrap)
             if (leftMeasurement.Type == SpacePlanType.Wrap)
                 return SpacePlan.Wrap();
                 return SpacePlan.Wrap();
 
 
-            if (leftMeasurement.Type == SpacePlanType.FullRender)
-                IsLeftRendered = true;
-            
             var rightMeasurement = Right.Measure(new Size(availableSpace.Width - leftMeasurement.Width, availableSpace.Height));
             var rightMeasurement = Right.Measure(new Size(availableSpace.Width - leftMeasurement.Width, availableSpace.Height));
 
 
             if (rightMeasurement.Type == SpacePlanType.Wrap)
             if (rightMeasurement.Type == SpacePlanType.Wrap)
                 return SpacePlan.Wrap();
                 return SpacePlan.Wrap();
-            
-            if (leftMeasurement.Type == SpacePlanType.FullRender)
-                IsRightRendered = true;
-            
+
             var totalWidth = leftMeasurement.Width + rightMeasurement.Width;
             var totalWidth = leftMeasurement.Width + rightMeasurement.Width;
             var totalHeight = Math.Max(leftMeasurement.Height, rightMeasurement.Height);
             var totalHeight = Math.Max(leftMeasurement.Height, rightMeasurement.Height);
 
 
@@ -82,14 +76,23 @@ namespace QuestPDF.Elements
 
 
         internal override void Draw(Size availableSpace)
         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);
+            
+            if (rightMeasurement.Type == SpacePlanType.FullRender)
+                IsRightRendered = true;
             
             
-            Canvas.Translate(new Position(leftWidth, 0));
-            Right.Draw(new Size(availableSpace.Width - leftWidth, availableSpace.Height));
-            Canvas.Translate(new Position(-leftWidth, 0));
+            Canvas.Translate(new Position(leftMeasurement.Width, 0));
+            Right.Draw(rightSpace);
+            Canvas.Translate(new Position(-leftMeasurement.Width, 0));
         }
         }
     }
     }
     
     

+ 16 - 34
QuestPDF/Elements/Table/Table.cs

@@ -15,15 +15,19 @@ namespace QuestPDF.Elements.Table
         public List<TableCell> Cells { get; set; } = new List<TableCell>();
         public List<TableCell> Cells { get; set; } = new List<TableCell>();
         public bool ExtendLastCellsToTableBottom { get; set; }
         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 StartingRowsCount { get; set; }
         private int RowsCount { get; set; }
         private int RowsCount { get; set; }
         private int CurrentRow { 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<Element?> GetChildren()
         internal override IEnumerable<Element?> GetChildren()
         {
         {
             return Cells;
             return Cells;
@@ -31,24 +35,6 @@ namespace QuestPDF.Elements.Table
 
 
         public void ResetState()
         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<TableCell>())
-                    .ToArray();   
-            }
-
             Cells.ForEach(x => x.IsRendered = false);
             Cells.ForEach(x => x.IsRendered = false);
             CurrentRow = 1;
             CurrentRow = 1;
         }
         }
@@ -85,6 +71,9 @@ namespace QuestPDF.Elements.Table
             {
             {
                 if (command.Measurement.Type == SpacePlanType.FullRender)
                 if (command.Measurement.Type == SpacePlanType.FullRender)
                     command.Cell.IsRendered = true;
                     command.Cell.IsRendered = true;
+
+                if (command.Measurement.Type == SpacePlanType.Wrap)
+                    continue;
                 
                 
                 Canvas.Translate(command.Offset);
                 Canvas.Translate(command.Offset);
                 command.Cell.Draw(command.Size);
                 command.Cell.Draw(command.Size);
@@ -103,7 +92,7 @@ namespace QuestPDF.Elements.Table
         {
         {
             return commands
             return commands
                 .GroupBy(x => x.Cell.Row)
                 .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)
                 .Select(x => x.Key)
                 .DefaultIfEmpty(0)
                 .DefaultIfEmpty(0)
                 .Max();
                 .Max();
@@ -152,16 +141,12 @@ namespace QuestPDF.Elements.Table
             ICollection<TableCellRenderingCommand> GetRenderingCommands()
             ICollection<TableCellRenderingCommand> GetRenderingCommands()
             {
             {
                 var rowBottomOffsets = new DynamicDictionary<int, float>();
                 var rowBottomOffsets = new DynamicDictionary<int, float>();
+                var commands = new List<TableCellRenderingCommand>();
                 
                 
-                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 currentRow = CurrentRow;
                 var maxRenderingRow = RowsCount;
                 var maxRenderingRow = RowsCount;
                 
                 
-                var commands = new List<TableCellRenderingCommand>();
-                
                 foreach (var cell in cellsToTry)
                 foreach (var cell in cellsToTry)
                 {
                 {
                     // update position of previous row
                     // update position of previous row
@@ -181,10 +166,7 @@ namespace QuestPDF.Elements.Table
                     // cell visibility optimizations
                     // cell visibility optimizations
                     if (cell.Row > maxRenderingRow)
                     if (cell.Row > maxRenderingRow)
                         break;
                         break;
-                    
-                    if (cell.IsRendered)
-                        continue;
-                    
+
                     // calculate cell position / size
                     // calculate cell position / size
                     var topOffset = rowBottomOffsets[cell.Row - 1];
                     var topOffset = rowBottomOffsets[cell.Row - 1];
                     
                     

+ 1 - 1
QuestPDF/Helpers/Placeholders.cs

@@ -7,7 +7,7 @@ namespace QuestPDF.Helpers
 {
 {
     public static class Placeholders
     public static class Placeholders
     {
     {
-        public static readonly Random Random = new Random(3); // 3
+        public static readonly Random Random = new();
         
         
         #region Word Cache
         #region Word Cache
 
 

+ 1 - 1
QuestPDF/Infrastructure/Element.cs

@@ -15,7 +15,7 @@ namespace QuestPDF.Infrastructure
             yield break;
             yield break;
         }
         }
 
 
-        internal void Initialize(IPageContext pageContext, ICanvas canvas)
+        internal virtual void Initialize(IPageContext pageContext, ICanvas canvas)
         {
         {
             PageContext = pageContext;
             PageContext = pageContext;
             Canvas = canvas;
             Canvas = canvas;

+ 1 - 1
QuestPDF/QuestPDF.csproj

@@ -4,7 +4,7 @@
         <Authors>MarcinZiabek</Authors>
         <Authors>MarcinZiabek</Authors>
         <Company>CodeFlint</Company>
         <Company>CodeFlint</Company>
         <PackageId>QuestPDF</PackageId>
         <PackageId>QuestPDF</PackageId>
-        <Version>2022.1.0-beta4</Version>
+        <Version>2022.1.0-beta5</Version>
         <PackageDescription>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.</PackageDescription>
         <PackageDescription>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.</PackageDescription>
         <PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt"))</PackageReleaseNotes>
         <PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt"))</PackageReleaseNotes>
         <LangVersion>9</LangVersion>
         <LangVersion>9</LangVersion>