Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| feab280a27 | |||
| 4152a0f701 | |||
| 6c80c59996 | |||
| 08a37666fe |
@@ -0,0 +1,46 @@
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class ContinuousPageDocument : IDocument
|
||||
{
|
||||
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||
|
||||
public void Compose(IDocumentContainer container)
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(20);
|
||||
page.ContinuousSize(150);
|
||||
|
||||
page.Header().Text("Header");
|
||||
|
||||
page.Content().PaddingVertical(10).Border(1).Padding(10).Stack(stack =>
|
||||
{
|
||||
foreach (var index in Enumerable.Range(1, 100))
|
||||
stack.Item().Text($"Line {index}", TextStyle.Default.Color(Placeholders.Color()));
|
||||
});
|
||||
|
||||
page.Footer().Text("Footer");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ContinuousPageExamples
|
||||
{
|
||||
[Test]
|
||||
public void ContinuousPage()
|
||||
{
|
||||
var path = "example.pdf";
|
||||
new ContinuousPageDocument().GeneratePdf(path);
|
||||
Process.Start("explorer", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,10 @@ namespace QuestPDF.Drawing
|
||||
var spacePlan = content.Measure(Size.Max) as Size;
|
||||
|
||||
if (spacePlan == null)
|
||||
break;
|
||||
{
|
||||
canvas.EndDocument();
|
||||
ThrowLayoutException();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -78,7 +81,7 @@ namespace QuestPDF.Drawing
|
||||
if (currentPage >= documentMetadata.DocumentLayoutExceptionThreshold)
|
||||
{
|
||||
canvas.EndDocument();
|
||||
throw new DocumentLayoutException("Composed layout generates infinite document.");
|
||||
ThrowLayoutException();
|
||||
}
|
||||
|
||||
if (spacePlan is FullRender)
|
||||
@@ -88,6 +91,11 @@ namespace QuestPDF.Drawing
|
||||
}
|
||||
|
||||
canvas.EndDocument();
|
||||
|
||||
void ThrowLayoutException()
|
||||
{
|
||||
throw new DocumentLayoutException("Composed layout generates infinite document.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
@@ -36,9 +37,20 @@ namespace QuestPDF.Elements
|
||||
.Decoration(decoration =>
|
||||
{
|
||||
decoration.Header().Element(Header);
|
||||
decoration.Content().Extend().Element(Content);
|
||||
|
||||
decoration
|
||||
.Content()
|
||||
.Element(x => IsClose(MinSize.Width, MaxSize.Width) ? x.ExtendHorizontal() : x)
|
||||
.Element(x => IsClose(MinSize.Height, MaxSize.Height) ? x.ExtendVertical() : x)
|
||||
.Element(Content);
|
||||
|
||||
decoration.Footer().Element(Footer);
|
||||
});
|
||||
|
||||
bool IsClose(float x, float y)
|
||||
{
|
||||
return Math.Abs(x - y) < Size.Epsilon;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
-44
@@ -7,29 +7,31 @@ using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Elements
|
||||
{
|
||||
internal abstract class RowElement : ContainerElement
|
||||
internal abstract class RowElement : Constrained
|
||||
{
|
||||
public float Width { get; set; } = 1;
|
||||
public float Size { get; protected set; }
|
||||
|
||||
internal override void Draw(Size availableSpace)
|
||||
public void SetWidth(float width)
|
||||
{
|
||||
Child?.Draw(availableSpace);
|
||||
MinWidth = width;
|
||||
MaxWidth = width;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ConstantRowElement : RowElement
|
||||
{
|
||||
public ConstantRowElement(float width)
|
||||
public ConstantRowElement(float size)
|
||||
{
|
||||
Width = width;
|
||||
Size = size;
|
||||
SetWidth(size);
|
||||
}
|
||||
}
|
||||
|
||||
internal class RelativeRowElement : RowElement
|
||||
{
|
||||
public RelativeRowElement(float width)
|
||||
public RelativeRowElement(float size)
|
||||
{
|
||||
Width = width;
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,70 +86,61 @@ namespace QuestPDF.Elements
|
||||
|
||||
internal class Row : Element
|
||||
{
|
||||
public ICollection<RowElement> Children { get; internal set; } = new List<RowElement>();
|
||||
public float Spacing { get; set; } = 0;
|
||||
|
||||
|
||||
public ICollection<RowElement> Children { get; internal set; } = new List<RowElement>();
|
||||
private Element? RootElement { get; set; }
|
||||
|
||||
internal override void HandleVisitor(Action<Element?> visit)
|
||||
{
|
||||
Children.ToList().ForEach(x => x.HandleVisitor(visit));
|
||||
if (RootElement == null)
|
||||
ComposeTree();
|
||||
|
||||
RootElement.HandleVisitor(visit);
|
||||
base.HandleVisitor(visit);
|
||||
}
|
||||
|
||||
internal override ISpacePlan Measure(Size availableSpace)
|
||||
{
|
||||
return Compose(availableSpace.Width).Measure(availableSpace);
|
||||
UpdateElementsWidth(availableSpace.Width);
|
||||
return RootElement.Measure(availableSpace);
|
||||
}
|
||||
|
||||
internal override void Draw(Size availableSpace)
|
||||
{
|
||||
Compose(availableSpace.Width).Draw(availableSpace);
|
||||
UpdateElementsWidth(availableSpace.Width);
|
||||
RootElement.Draw(availableSpace);
|
||||
}
|
||||
|
||||
#region structure
|
||||
|
||||
private Element Compose(float availableWidth)
|
||||
private void ComposeTree()
|
||||
{
|
||||
var elements = AddSpacing(Children, Spacing);
|
||||
var rowElements = ReduceRows(elements, availableWidth);
|
||||
var tree = BuildTree(rowElements.ToArray());
|
||||
tree.HandleVisitor(x => x.Initialize(PageContext, Canvas));
|
||||
Children = AddSpacing(Children, Spacing);
|
||||
|
||||
return tree;
|
||||
var elements = Children.Cast<Element>().ToArray();
|
||||
RootElement = BuildTree(elements);
|
||||
}
|
||||
|
||||
private static ICollection<Element> ReduceRows(ICollection<RowElement> elements, float availableWidth)
|
||||
|
||||
private void UpdateElementsWidth(float availableWidth)
|
||||
{
|
||||
var constantWidth = elements
|
||||
var constantWidth = Children
|
||||
.Where(x => x is ConstantRowElement)
|
||||
.Cast<ConstantRowElement>()
|
||||
.Sum(x => x.Width);
|
||||
.Sum(x => x.Size);
|
||||
|
||||
var relativeWidth = elements
|
||||
var relativeWidth = Children
|
||||
.Where(x => x is RelativeRowElement)
|
||||
.Cast<RelativeRowElement>()
|
||||
.Sum(x => x.Width);
|
||||
.Sum(x => x.Size);
|
||||
|
||||
var widthPerRelativeUnit = (availableWidth - constantWidth) / relativeWidth;
|
||||
|
||||
return elements
|
||||
.Select(x =>
|
||||
{
|
||||
if (x is RelativeRowElement r)
|
||||
return new ConstantRowElement(r.Width * widthPerRelativeUnit)
|
||||
{
|
||||
Child = x.Child
|
||||
};
|
||||
|
||||
return x;
|
||||
})
|
||||
.Select(x => new Constrained
|
||||
{
|
||||
MinWidth = x.Width,
|
||||
MaxWidth = x.Width,
|
||||
Child = x.Child
|
||||
})
|
||||
.Cast<Element>()
|
||||
.ToList();
|
||||
Children
|
||||
.Where(x => x is RelativeRowElement)
|
||||
.Cast<RelativeRowElement>()
|
||||
.ToList()
|
||||
.ForEach(x => x.SetWidth(x.Size * widthPerRelativeUnit));
|
||||
}
|
||||
|
||||
private static ICollection<RowElement> AddSpacing(ICollection<RowElement> elements, float spacing)
|
||||
|
||||
@@ -18,10 +18,10 @@ namespace QuestPDF.Fluent
|
||||
{
|
||||
if (element?.Child != null && element.Child is Empty == false)
|
||||
{
|
||||
var message = $"Container {element.GetType().Name} already contains an {element.Child.GetType().Name} child. " +
|
||||
$"Tried to assign {child?.GetType()?.Name}." +
|
||||
$"You should not assign multiple elements to single-child containers.";
|
||||
|
||||
var message = "You should not assign multiple child elements to a single-child container. " +
|
||||
"This may happen when a container variable is used outside of its scope/closure OR the container is used in multiple fluent API chains OR the container is used incorrectly in a loop. " +
|
||||
"This exception is thrown to help you detect that some part of the code is overriding fragments of the document layout with a new content - essentially destroying existing content.";
|
||||
|
||||
throw new DocumentComposeException(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,24 @@ namespace QuestPDF.Fluent
|
||||
|
||||
public void Size(PageSize pageSize)
|
||||
{
|
||||
Page.MinSize = pageSize;
|
||||
Page.MaxSize = pageSize;
|
||||
MinSize(pageSize);
|
||||
MaxSize(pageSize);
|
||||
}
|
||||
|
||||
|
||||
public void ContinuousSize(float width)
|
||||
{
|
||||
Page.MinSize = new PageSize(width, 0);
|
||||
Page.MaxSize = new PageSize(width, Infrastructure.Size.Max.Height);
|
||||
MinSize(new PageSize(width, 0));
|
||||
MaxSize(new PageSize(width, Infrastructure.Size.Max.Height));
|
||||
}
|
||||
|
||||
public void MinSize(PageSize pageSize)
|
||||
{
|
||||
Page.MinSize = pageSize;
|
||||
}
|
||||
|
||||
public void MaxSize(PageSize pageSize)
|
||||
{
|
||||
Page.MaxSize = pageSize;
|
||||
}
|
||||
|
||||
public void MarginLeft(float value)
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<Authors>MarcinZiabek</Authors>
|
||||
<Company>CodeFlint</Company>
|
||||
<PackageId>QuestPDF</PackageId>
|
||||
<Version>2021.9.0</Version>
|
||||
<Version>2021.9.3</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>
|
||||
<PackageReleaseNotes>Added support for registering custom fonts from a stream.</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>Added support for registering custom fonts from a stream. Fixed continuous page setting. Improved exception messages.</PackageReleaseNotes>
|
||||
<LangVersion>8</LangVersion>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageIcon>Logo.png</PackageIcon>
|
||||
|
||||
Reference in New Issue
Block a user