Browse Source

Implemented element to measure and draw overflow area

Marcin Ziąbek 2 years ago
parent
commit
71801a17d0

+ 41 - 0
Source/QuestPDF.Examples/ElementExamples.cs

@@ -843,5 +843,46 @@ namespace QuestPDF.Examples
                         });
                 });
         }
+        
+        [Test]
+        public void DrawOverflow()
+        {
+            RenderingTest
+                .Create()
+                .ShowResults()
+                .ProducePdf()
+                .RenderDocument(document =>
+                {
+                    document.Page(page =>
+                    {
+                        page.Size(PageSizes.A4);
+                        page.Margin(24);
+                        page.DefaultTextStyle(TextStyle.Default.FontSize(16));
+
+                        page.Header().Text("Document header").FontSize(24).Bold().FontColor(Colors.Blue.Accent2);
+
+                        page.Content().PaddingVertical(24).Column(column =>
+                        {
+                            column.Spacing(16);
+
+                            foreach (var size in Enumerable.Range(20, 20))
+                                column.Item().Width(size * 10).Height(40).Background(Colors.Grey.Lighten3);
+                            
+                            column.Item().Row(row =>
+                            {
+                                row.RelativeItem().Border(1).Background(Colors.Grey.Lighten3).Padding(5).Text("Will it work?").FontSize(20);
+                                row.RelativeItem().Border(1).Background(Colors.Grey.Lighten3).Padding(5).ContentOverflowDebugArea().ShowEntire().Text(Placeholders.LoremIpsum()).FontSize(20);
+                            });
+                        });
+                        
+                        page.Footer().AlignCenter().Text(text =>
+                        {
+                            text.CurrentPageNumber();
+                            text.Span(" / ");
+                            text.TotalPages();
+                        });
+                    });
+                });
+        }
     }
 }

+ 129 - 0
Source/QuestPDF/Elements/DrawOverflow.cs

@@ -0,0 +1,129 @@
+using System;
+using System.Linq;
+using QuestPDF.Drawing;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Elements;
+
+internal class ContentOverflowDebugArea : ContainerElement
+{
+    internal override SpacePlan Measure(Size availableSpace)
+    {
+        var childSize = base.Measure(availableSpace);
+        
+        if (childSize.Type == SpacePlanType.Wrap)
+            return SpacePlan.FullRender(availableSpace);
+
+        return childSize;
+    }
+        
+    internal override void Draw(Size availableSpace)
+    {
+        var childSize = base.Measure(availableSpace);
+
+        if (childSize.Type != SpacePlanType.Wrap)
+        {
+            Child?.Draw(availableSpace);
+            return;
+        }
+        
+        var overflowSpace = TryVerticalOverflow(availableSpace) 
+            ?? TryVerticalOverflow(availableSpace) 
+            ?? TryExpandedOverflow(availableSpace) 
+            ?? Size.Max;
+        
+        Child?.Draw(overflowSpace);
+
+        DrawTargetAreaBorder(overflowSpace);
+        DrawOverflowArea(availableSpace, overflowSpace);
+    }
+
+    private Size? TryOverflow(Size targetSpace)
+    {
+        var contentSize = base.Measure(targetSpace);
+        return contentSize.Type == SpacePlanType.Wrap ? null : contentSize;
+    }
+    
+    private Size? TryVerticalOverflow(Size availableSpace)
+    {
+        var overflowSpace = new Size(availableSpace.Width, Size.Infinity);
+        return TryOverflow(overflowSpace);
+    }
+    
+    private Size? TryHorizontalOverflow(Size availableSpace)
+    {
+        var overflowSpace = new Size(Size.Infinity, availableSpace.Height);
+        return TryOverflow(overflowSpace);
+    }
+    
+    private Size? TryExpandedOverflow(Size availableSpace)
+    {
+        var overflowSpace = new Size(Size.Infinity, Size.Infinity);
+        return TryOverflow(overflowSpace);
+    }
+    
+    private void DrawTargetAreaBorder(Size contentSize)
+    {
+        const float borderWidth = 2;
+        const string borderColor = "#f44336";
+        
+        Canvas.DrawRectangle(
+            new Position(-borderWidth/2, -borderWidth/2), 
+            new Size(contentSize.Width + borderWidth/2 + borderWidth/2, borderWidth), 
+            borderColor);
+            
+        Canvas.DrawRectangle(
+            new Position(-borderWidth/2, -borderWidth/2), 
+            new Size(borderWidth, contentSize.Height + borderWidth/2 + borderWidth/2), 
+            borderColor);
+            
+        Canvas.DrawRectangle(
+            new Position(-borderWidth/2, contentSize.Height-borderWidth/2), 
+            new Size(contentSize.Width + borderWidth/2 + borderWidth/2, borderWidth), 
+            borderColor);
+            
+        Canvas.DrawRectangle(
+            new Position(contentSize.Width-borderWidth/2, -borderWidth/2), 
+            new Size(borderWidth, contentSize.Height + borderWidth/2 + borderWidth/2), 
+            borderColor);
+    }
+    
+    private void DrawOverflowArea(Size availableSpace, Size contentSize)
+    {
+        const float checkerboardSize = 8;
+
+        const string lightCellColor = "#44f44336";
+        const string darkCellColor = "#88f44336";
+        
+        var overflowPosition = new Position(0, availableSpace.Height);
+        var overflowSize = new Size(contentSize.Width, contentSize.Height - availableSpace.Height);
+        
+        var boardSizeX = (int)Math.Ceiling(overflowSize.Width / checkerboardSize);
+        var boardSizeY = (int)Math.Ceiling(overflowSize.Height / checkerboardSize);
+        
+        Canvas.Translate(overflowPosition);
+        
+        foreach (var x in Enumerable.Range(0, boardSizeX))
+        {
+            foreach (var y in Enumerable.Range(0, boardSizeY))
+            {
+                var cellColor = (x + y) % 2 == 0 ? lightCellColor : darkCellColor;
+
+                var cellPosition = new Position(
+                    x * checkerboardSize, 
+                    y * checkerboardSize);
+
+                var isLastCellX = x + 1 == boardSizeX;
+                var isLastCellY = y + 1 == boardSizeY;
+                
+                var cellSize = new Size(
+                    isLastCellX ? overflowSize.Width - x * checkerboardSize : checkerboardSize, 
+                    isLastCellY ? overflowSize.Height - y * checkerboardSize : checkerboardSize);
+                
+                Canvas.DrawRectangle(cellPosition, cellSize, cellColor);
+            }
+        }
+        
+        Canvas.Translate(overflowPosition.Reverse());
+    }
+}

+ 5 - 0
Source/QuestPDF/Fluent/ElementExtensions.cs

@@ -374,5 +374,10 @@ namespace QuestPDF.Fluent
         {
             return element.Element(new ScaleToFit());
         }
+        
+        internal static IContainer ContentOverflowDebugArea(this IContainer element)
+        {
+            return element.Element(new ContentOverflowDebugArea());
+        }
     }
 }