From cb493562fcf3b8e56e5d2d989f1e2ceb3b630187 Mon Sep 17 00:00:00 2001 From: Xaver Schulz Date: Fri, 10 Dec 2021 21:07:42 +0100 Subject: [PATCH 01/17] fix rendering direct to aspnet core response stream adding a WrapperStream to support streams that not implement the Position property needed by SkiaSharp. e.g. useful for the aspnet core response stream fix #52 --- QuestPDF/Drawing/PdfCanvas.cs | 4 +- QuestPDF/Drawing/XpsCanvas.cs | 4 +- QuestPDF/Helpers/WriteStreamWrapper.cs | 53 ++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 QuestPDF/Helpers/WriteStreamWrapper.cs diff --git a/QuestPDF/Drawing/PdfCanvas.cs b/QuestPDF/Drawing/PdfCanvas.cs index fd7b1df..ca7cf6b 100644 --- a/QuestPDF/Drawing/PdfCanvas.cs +++ b/QuestPDF/Drawing/PdfCanvas.cs @@ -1,5 +1,5 @@ using System.IO; -using QuestPDF.Infrastructure; +using QuestPDF.Helpers; using SkiaSharp; namespace QuestPDF.Drawing @@ -7,7 +7,7 @@ namespace QuestPDF.Drawing internal class PdfCanvas : SkiaDocumentCanvasBase { public PdfCanvas(Stream stream, DocumentMetadata documentMetadata) - : base(SKDocument.CreatePdf(stream, MapMetadata(documentMetadata))) + : base(SKDocument.CreatePdf(new WriteStreamWrapper(stream), MapMetadata(documentMetadata))) { } diff --git a/QuestPDF/Drawing/XpsCanvas.cs b/QuestPDF/Drawing/XpsCanvas.cs index c885ef8..044f5bf 100644 --- a/QuestPDF/Drawing/XpsCanvas.cs +++ b/QuestPDF/Drawing/XpsCanvas.cs @@ -1,5 +1,5 @@ using System.IO; -using QuestPDF.Infrastructure; +using QuestPDF.Helpers; using SkiaSharp; namespace QuestPDF.Drawing @@ -7,7 +7,7 @@ namespace QuestPDF.Drawing internal class XpsCanvas : SkiaDocumentCanvasBase { public XpsCanvas(Stream stream, DocumentMetadata documentMetadata) - : base(SKDocument.CreateXps(stream, documentMetadata.RasterDpi)) + : base(SKDocument.CreateXps(new WriteStreamWrapper(stream), documentMetadata.RasterDpi)) { } diff --git a/QuestPDF/Helpers/WriteStreamWrapper.cs b/QuestPDF/Helpers/WriteStreamWrapper.cs new file mode 100644 index 0000000..e4ce5c9 --- /dev/null +++ b/QuestPDF/Helpers/WriteStreamWrapper.cs @@ -0,0 +1,53 @@ +using System; +using System.IO; + +namespace QuestPDF.Helpers +{ + internal class WriteStreamWrapper : Stream + { + private readonly Stream _innerStream; + + private long _length; + + public WriteStreamWrapper(Stream stream) + { + if (!stream.CanWrite) + { + throw new NotSupportedException("Stream cannot be written"); + } + + _innerStream = stream; + } + + public override bool CanRead => false; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => _length; + + public override long Position { + get => _length; + set => throw new NotImplementedException(); + } + + public override void Flush() + => _innerStream.Flush(); + + public override int Read(byte[] buffer, int offset, int count) + => throw new NotImplementedException(); + + public override long Seek(long offset, SeekOrigin origin) + => throw new NotImplementedException(); + + public override void SetLength(long value) + => throw new NotImplementedException(); + + public override void Write(byte[] buffer, int offset, int count) + { + _innerStream.Write(buffer, offset, count); + _length += count; + } + } +} From 648a359d15459267b4e321efb6f3f6585c7f1c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Thu, 6 Jan 2022 22:19:33 +0100 Subject: [PATCH 02/17] Implemented the PreventPaging element --- QuestPDF/Elements/PreventPaging.cs | 25 +++++++++++++++++++++++++ QuestPDF/Fluent/ElementExtensions.cs | 5 +++++ 2 files changed, 30 insertions(+) create mode 100644 QuestPDF/Elements/PreventPaging.cs diff --git a/QuestPDF/Elements/PreventPaging.cs b/QuestPDF/Elements/PreventPaging.cs new file mode 100644 index 0000000..e4c0327 --- /dev/null +++ b/QuestPDF/Elements/PreventPaging.cs @@ -0,0 +1,25 @@ +using System; +using QuestPDF.Drawing; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Elements +{ + internal class PreventPaging : ContainerElement + { + internal override SpacePlan Measure(Size availableSpace) + { + if (Child == null) + return SpacePlan.FullRender(Size.Zero); + + var measurement = Child.Measure(availableSpace); + + return measurement.Type switch + { + SpacePlanType.Wrap => SpacePlan.FullRender(Size.Zero), + SpacePlanType.PartialRender => SpacePlan.FullRender(measurement), + SpacePlanType.FullRender => measurement, + _ => throw new ArgumentOutOfRangeException() + }; + } + } +} \ No newline at end of file diff --git a/QuestPDF/Fluent/ElementExtensions.cs b/QuestPDF/Fluent/ElementExtensions.cs index 856585d..d9a2a06 100644 --- a/QuestPDF/Fluent/ElementExtensions.cs +++ b/QuestPDF/Fluent/ElementExtensions.cs @@ -160,5 +160,10 @@ namespace QuestPDF.Fluent TextStyle = textStyle }); } + + public static IContainer PreventPaging(this IContainer element) + { + return element.Element(new PreventPaging()); + } } } From ba8b35b1c009474e22b91c57539bbdef1634acd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Fri, 7 Jan 2022 00:09:25 +0100 Subject: [PATCH 03/17] Implemented ScaleToFit element --- QuestPDF.Examples/ScaleToFitExamples.cs | 42 +++++++++++++ QuestPDF/Elements/ScaleToFit.cs | 78 +++++++++++++++++++++++++ QuestPDF/Fluent/ElementExtensions.cs | 5 ++ 3 files changed, 125 insertions(+) create mode 100644 QuestPDF.Examples/ScaleToFitExamples.cs create mode 100644 QuestPDF/Elements/ScaleToFit.cs diff --git a/QuestPDF.Examples/ScaleToFitExamples.cs b/QuestPDF.Examples/ScaleToFitExamples.cs new file mode 100644 index 0000000..a5017d0 --- /dev/null +++ b/QuestPDF.Examples/ScaleToFitExamples.cs @@ -0,0 +1,42 @@ +using System.Linq; +using NUnit.Framework; +using QuestPDF.Examples.Engine; +using QuestPDF.Fluent; +using QuestPDF.Helpers; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Examples +{ + public class ScaleToFitExamples + { + [Test] + public void ScaleToFit() + { + RenderingTest + .Create() + .PageSize(PageSizes.A4) + .ProducePdf() + .ShowResults() + .Render(container => + { + container.Padding(25).Stack(stack => + { + var text = Placeholders.Paragraph(); + + foreach (var i in Enumerable.Range(0, 16)) + { + stack + .Item() + .MinimalBox() + .Border(1) + .Padding(5) + .Width(50 + i * 25) + .Height(25 + i * 5) + .ScaleToFit() + .Text(text); + } + }); + }); + } + } +} \ No newline at end of file diff --git a/QuestPDF/Elements/ScaleToFit.cs b/QuestPDF/Elements/ScaleToFit.cs new file mode 100644 index 0000000..354df6b --- /dev/null +++ b/QuestPDF/Elements/ScaleToFit.cs @@ -0,0 +1,78 @@ +using System; +using System.Linq; +using QuestPDF.Drawing; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Elements +{ + internal class ScaleToFit : ContainerElement + { + internal override SpacePlan Measure(Size availableSpace) + { + if (Child == null) + return SpacePlan.FullRender(Size.Zero); + + var perfectScale = FindPerfectScale(Child, availableSpace); + + if (perfectScale == null) + return SpacePlan.Wrap(); + + var targetSpace = ScaleSize(availableSpace, perfectScale.Value); + return SpacePlan.FullRender(targetSpace); + } + + internal override void Draw(Size availableSpace) + { + var perfectScale = FindPerfectScale(Child, availableSpace); + + if (!perfectScale.HasValue) + return; + + var targetScale = perfectScale.Value; + var targetSpace = ScaleSize(availableSpace, 1 / targetScale); + + Canvas.Scale(targetScale, targetScale); + Child?.Draw(targetSpace); + Canvas.Scale(1 / targetScale, 1 / targetScale); + } + + private static Size ScaleSize(Size size, float factor) + { + return new Size(size.Width * factor, size.Height * factor); + } + + private static float? FindPerfectScale(Element child, Size availableSpace) + { + if (ChildFits(1)) + return 1; + + var maxScale = 1f; + var minScale = Size.Epsilon; + + var lastWorkingScale = (float?)null; + + foreach (var _ in Enumerable.Range(0, 8)) + { + var halfScale = (maxScale + minScale) / 2; + + if (ChildFits(halfScale)) + { + minScale = halfScale; + lastWorkingScale = halfScale; + } + else + { + maxScale = halfScale; + } + } + + return lastWorkingScale; + + bool ChildFits(float scale) + { + var scaledSpace = ScaleSize(availableSpace, 1 / scale); + return child.Measure(scaledSpace).Type == SpacePlanType.FullRender; + } + } + } +} \ No newline at end of file diff --git a/QuestPDF/Fluent/ElementExtensions.cs b/QuestPDF/Fluent/ElementExtensions.cs index d9a2a06..54fc738 100644 --- a/QuestPDF/Fluent/ElementExtensions.cs +++ b/QuestPDF/Fluent/ElementExtensions.cs @@ -165,5 +165,10 @@ namespace QuestPDF.Fluent { return element.Element(new PreventPaging()); } + + public static IContainer ScaleToFit(this IContainer element) + { + return element.Element(new ScaleToFit()); + } } } From a2ce31022c280d45eadb30d537f0c5bfb4f0458d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Sat, 8 Jan 2022 01:11:25 +0100 Subject: [PATCH 04/17] Improved default behavior of fluent configuration --- QuestPDF/Fluent/PaddingExtensions.cs | 8 ++++---- QuestPDF/Fluent/ScaleExtensions.cs | 4 ++-- QuestPDF/Fluent/TranslateExtensions.cs | 4 ++-- QuestPDF/Resources/ReleaseNotes.txt | 9 ++------- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/QuestPDF/Fluent/PaddingExtensions.cs b/QuestPDF/Fluent/PaddingExtensions.cs index 6f4b579..4cdc892 100644 --- a/QuestPDF/Fluent/PaddingExtensions.cs +++ b/QuestPDF/Fluent/PaddingExtensions.cs @@ -31,22 +31,22 @@ namespace QuestPDF.Fluent public static IContainer PaddingTop(this IContainer element, float value) { - return element.Padding(x => x.Top = value); + return element.Padding(x => x.Top += value); } public static IContainer PaddingBottom(this IContainer element, float value) { - return element.Padding(x => x.Bottom = value); + return element.Padding(x => x.Bottom += value); } public static IContainer PaddingLeft(this IContainer element, float value) { - return element.Padding(x => x.Left = value); + return element.Padding(x => x.Left += value); } public static IContainer PaddingRight(this IContainer element, float value) { - return element.Padding(x => x.Right = value); + return element.Padding(x => x.Right += value); } } } \ No newline at end of file diff --git a/QuestPDF/Fluent/ScaleExtensions.cs b/QuestPDF/Fluent/ScaleExtensions.cs index 58ae16a..eb8eb74 100644 --- a/QuestPDF/Fluent/ScaleExtensions.cs +++ b/QuestPDF/Fluent/ScaleExtensions.cs @@ -21,7 +21,7 @@ namespace QuestPDF.Fluent public static IContainer ScaleHorizontal(this IContainer element, float value) { - return element.Scale(x => x.ScaleX = value); + return element.Scale(x => x.ScaleX *= value); } public static IContainer FlipHorizontal(this IContainer element) @@ -31,7 +31,7 @@ namespace QuestPDF.Fluent public static IContainer ScaleVertical(this IContainer element, float value) { - return element.Scale(x => x.ScaleY = value); + return element.Scale(x => x.ScaleY *= value); } public static IContainer FlipVertical(this IContainer element) diff --git a/QuestPDF/Fluent/TranslateExtensions.cs b/QuestPDF/Fluent/TranslateExtensions.cs index 401eade..bb2c148 100644 --- a/QuestPDF/Fluent/TranslateExtensions.cs +++ b/QuestPDF/Fluent/TranslateExtensions.cs @@ -16,12 +16,12 @@ namespace QuestPDF.Fluent public static IContainer TranslateX(this IContainer element, float value) { - return element.Translate(x => x.TranslateX = value); + return element.Translate(x => x.TranslateX += value); } public static IContainer TranslateY(this IContainer element, float value) { - return element.Translate(x => x.TranslateY = value); + return element.Translate(x => x.TranslateY += value); } } } \ No newline at end of file diff --git a/QuestPDF/Resources/ReleaseNotes.txt b/QuestPDF/Resources/ReleaseNotes.txt index ad04a83..b6a838c 100644 --- a/QuestPDF/Resources/ReleaseNotes.txt +++ b/QuestPDF/Resources/ReleaseNotes.txt @@ -1,7 +1,2 @@ -Introduced new element: `Table` - a great way to construct complex document structures, e.g. reports. This element covers all cases offered by combination of the `Stack` and the `Row` elements. Additionally, it provides support for more complex layouts and corner cases. Updating to the `Table` element can greatly simplify your code 😁 - -Other changes: -- Added new element `DefaultTextStyle` - it allows set new text style to all its children, -- Improved the default paging behavior for the `Row` element. In some minor corner cases it might cause infinite layout exceptions and confuse developers. -- Improved the `Row` element: added new type of column that combines constant and relative widths. -- Fixed default page sizes for: Letter and Legal. +- Added a `ScaleToFit` element - scales it child down so it does fit in the provided space, +- Improved default Fluent configuration behavior for elements: Scale, Padding, Translate. \ No newline at end of file From f8057a840c94019f037299a2f6588370fe86c4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Sun, 9 Jan 2022 00:11:34 +0100 Subject: [PATCH 05/17] Added: Line, Reimplemented: Column, Row and Decoration --- QuestPDF.Examples/ChartExamples.cs | 6 +- QuestPDF.Examples/ColumnExamples.cs | 36 +++ QuestPDF.Examples/ComplexLayoutBenchmark.cs | 10 +- QuestPDF.Examples/ContinousPage.cs | 4 +- QuestPDF.Examples/DebuggingTesting.cs | 4 +- QuestPDF.Examples/DefaultTextStyleExample.cs | 8 +- QuestPDF.Examples/DefaultTextStyleExamples.cs | 8 +- .../DifferentHeaderOnFirstPageExample.cs | 12 +- QuestPDF.Examples/ElementExamples.cs | 88 +++---- QuestPDF.Examples/EnsureSpaceExample.cs | 6 +- QuestPDF.Examples/FrameExample.cs | 8 +- QuestPDF.Examples/ImageExamples.cs | 10 +- QuestPDF.Examples/LineExamples.cs | 50 ++++ QuestPDF.Examples/LoremPicsumExample.cs | 2 +- QuestPDF.Examples/Padding.cs | 12 +- QuestPDF.Examples/RowExamples.cs | 41 ++- QuestPDF.Examples/ScaleToFitExamples.cs | 4 +- QuestPDF.Examples/ShowOnceExample.cs | 4 +- QuestPDF.Examples/SkipOnceExample.cs | 6 +- QuestPDF.Examples/TextBenchmark.cs | 54 ++-- QuestPDF.Examples/TextExamples.cs | 2 +- .../Layouts/DifferentHeadersTemplate.cs | 42 +-- .../Layouts/PhotoTemplate.cs | 18 +- .../Layouts/SectionTemplate.cs | 20 +- .../Layouts/StandardReport.cs | 32 +-- .../Layouts/TableOfContentsTemplate.cs | 14 +- QuestPDF.ReportSample/Tests.cs | 2 +- QuestPDF.UnitTests/GridTests.cs | 108 ++++---- QuestPDF.UnitTests/RowTests.cs | 30 +-- QuestPDF.UnitTests/StackTests.cs | 54 ++-- QuestPDF/Drawing/DocumentContainer.cs | 6 +- QuestPDF/Elements/Column.cs | 118 +++++++++ QuestPDF/Elements/Decoration.cs | 132 +++++----- QuestPDF/Elements/DecorationOld.cs | 101 ++++++++ QuestPDF/Elements/Grid.cs | 12 +- QuestPDF/Elements/Line.cs | 45 ++++ QuestPDF/Elements/PreventPaging.cs | 25 -- QuestPDF/Elements/Row.cs | 240 ++++++++---------- QuestPDF/Elements/RowOld.cs | 179 +++++++++++++ QuestPDF/Elements/Stack.cs | 8 +- QuestPDF/Fluent/ColumnExtensions.cs | 47 ++++ QuestPDF/Fluent/DecorationExtensions.cs | 2 +- QuestPDF/Fluent/ElementExtensions.cs | 7 +- QuestPDF/Fluent/LineExtensions.cs | 36 +++ QuestPDF/Fluent/RowExtensions.cs | 51 +++- QuestPDF/Fluent/RowOldExtensions.cs | 44 ++++ QuestPDF/Fluent/StackExtensions.cs | 33 --- QuestPDF/Fluent/TextExtensions.cs | 6 +- QuestPDF/Resources/Description.md | 14 +- 49 files changed, 1202 insertions(+), 599 deletions(-) create mode 100644 QuestPDF.Examples/ColumnExamples.cs create mode 100644 QuestPDF.Examples/LineExamples.cs create mode 100644 QuestPDF/Elements/Column.cs create mode 100644 QuestPDF/Elements/DecorationOld.cs create mode 100644 QuestPDF/Elements/Line.cs delete mode 100644 QuestPDF/Elements/PreventPaging.cs create mode 100644 QuestPDF/Elements/RowOld.cs create mode 100644 QuestPDF/Fluent/ColumnExtensions.cs create mode 100644 QuestPDF/Fluent/LineExtensions.cs create mode 100644 QuestPDF/Fluent/RowOldExtensions.cs delete mode 100644 QuestPDF/Fluent/StackExtensions.cs diff --git a/QuestPDF.Examples/ChartExamples.cs b/QuestPDF.Examples/ChartExamples.cs index 2d61057..a8eac35 100644 --- a/QuestPDF.Examples/ChartExamples.cs +++ b/QuestPDF.Examples/ChartExamples.cs @@ -52,14 +52,14 @@ namespace QuestPDF.Examples container .Background(Colors.White) .Padding(25) - .Stack(stack => + .Column(column => { - stack + column .Item() .PaddingBottom(10) .Text("Chart example", TextStyle.Default.Size(20).SemiBold().Color(Colors.Blue.Medium)); - stack + column .Item() .Border(1) .ExtendHorizontal() diff --git a/QuestPDF.Examples/ColumnExamples.cs b/QuestPDF.Examples/ColumnExamples.cs new file mode 100644 index 0000000..40d60b4 --- /dev/null +++ b/QuestPDF.Examples/ColumnExamples.cs @@ -0,0 +1,36 @@ +using NUnit.Framework; +using QuestPDF.Examples.Engine; +using QuestPDF.Fluent; +using QuestPDF.Helpers; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Examples +{ + public class ColumnExamples + { + [Test] + public void Column() + { + RenderingTest + .Create() + .PageSize(PageSizes.A4) + .ShowResults() + .ProducePdf() + .Render(container => + { + container.Column(column => + { + column.Item().Element(Block); + + static void Block(IContainer container) + { + container + .Width(100) + .Height(100) + .Background(Placeholders.BackgroundColor()); + } + }); + }); + } + } +} \ No newline at end of file diff --git a/QuestPDF.Examples/ComplexLayoutBenchmark.cs b/QuestPDF.Examples/ComplexLayoutBenchmark.cs index 60538f4..fb5fd19 100644 --- a/QuestPDF.Examples/ComplexLayoutBenchmark.cs +++ b/QuestPDF.Examples/ComplexLayoutBenchmark.cs @@ -36,8 +36,8 @@ namespace QuestPDF.Examples .BorderColor(Colors.Black) .Row(row => { - row.RelativeColumn().Element(x => GenerateStructure(x, level)); - row.RelativeColumn().Element(x => GenerateStructure(x, level)); + row.RelativeItem().Element(x => GenerateStructure(x, level)); + row.RelativeItem().Element(x => GenerateStructure(x, level)); }); } else @@ -45,10 +45,10 @@ namespace QuestPDF.Examples container .Border(level / 4f) .BorderColor(Colors.Black) - .Stack(stack => + .Column(column => { - stack.Item().Element(x => GenerateStructure(x, level)); - stack.Item().Element(x => GenerateStructure(x, level)); + column.Item().Element(x => GenerateStructure(x, level)); + column.Item().Element(x => GenerateStructure(x, level)); }); } } diff --git a/QuestPDF.Examples/ContinousPage.cs b/QuestPDF.Examples/ContinousPage.cs index 5593d5f..1e5c545 100644 --- a/QuestPDF.Examples/ContinousPage.cs +++ b/QuestPDF.Examples/ContinousPage.cs @@ -22,10 +22,10 @@ namespace QuestPDF.Examples page.Header().Text("Header"); - page.Content().PaddingVertical(10).Border(1).Padding(10).Stack(stack => + page.Content().PaddingVertical(10).Border(1).Padding(10).Column(column => { foreach (var index in Enumerable.Range(1, 100)) - stack.Item().Text($"Line {index}", TextStyle.Default.Color(Placeholders.Color())); + column.Item().Text($"Line {index}", TextStyle.Default.Color(Placeholders.Color())); }); page.Footer().Text("Footer"); diff --git a/QuestPDF.Examples/DebuggingTesting.cs b/QuestPDF.Examples/DebuggingTesting.cs index cecaa95..7aa2deb 100644 --- a/QuestPDF.Examples/DebuggingTesting.cs +++ b/QuestPDF.Examples/DebuggingTesting.cs @@ -9,7 +9,7 @@ namespace QuestPDF.Examples public class DebuggingTesting { [Test] - public void Stack() + public void column() { Assert.Throws(() => { @@ -23,7 +23,7 @@ namespace QuestPDF.Examples .Width(100) .Background(Colors.Grey.Lighten3) .DebugPointer("Example debug pointer") - .Stack(x => + .Column(x => { x.Item().Text("Test"); x.Item().Width(150); diff --git a/QuestPDF.Examples/DefaultTextStyleExample.cs b/QuestPDF.Examples/DefaultTextStyleExample.cs index c88f59c..e7db9eb 100644 --- a/QuestPDF.Examples/DefaultTextStyleExample.cs +++ b/QuestPDF.Examples/DefaultTextStyleExample.cs @@ -13,7 +13,7 @@ namespace QuestPDF.Examples { RenderingTest .Create() - .ProduceImages() + .ProducePdf() .ShowResults() .RenderDocument(container => { @@ -26,11 +26,11 @@ namespace QuestPDF.Examples page.Size(PageSizes.A4); page.Background(Colors.White); - page.Content().Stack(stack => + page.Content().Column(column => { - stack.Item().Text(Placeholders.Sentence()); + column.Item().Text(Placeholders.Sentence()); - stack.Item().Text(text => + column.Item().Text(text => { // text in this block is additionally semibold text.DefaultTextStyle(TextStyle.Default.SemiBold()); diff --git a/QuestPDF.Examples/DefaultTextStyleExamples.cs b/QuestPDF.Examples/DefaultTextStyleExamples.cs index dae5325..4165a39 100644 --- a/QuestPDF.Examples/DefaultTextStyleExamples.cs +++ b/QuestPDF.Examples/DefaultTextStyleExamples.cs @@ -24,12 +24,12 @@ namespace QuestPDF.Examples container .Padding(10) .DefaultTextStyle(TextStyle.Default.Bold().Underline()) - .Stack(stack => + .Column(column => { - stack.Item().Text("Default style applies to all children", TextStyle.Default); - stack.Item().Text("You can override certain styles", TextStyle.Default.Underline(false).Color(Colors.Green.Darken2)); + column.Item().Text("Default style applies to all children", TextStyle.Default); + column.Item().Text("You can override certain styles", TextStyle.Default.Underline(false).Color(Colors.Green.Darken2)); - stack.Item().PaddingTop(10).Border(1).Grid(grid => + column.Item().PaddingTop(10).Border(1).Grid(grid => { grid.Columns(4); diff --git a/QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs b/QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs index 9cae448..0f0c354 100644 --- a/QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs +++ b/QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs @@ -26,18 +26,18 @@ namespace QuestPDF.Examples page.Margin(30); page.Background(Colors.White); - page.Header().Stack(stack => + page.Header().Column(column => { - stack.Item().ShowOnce().Background(Colors.Blue.Lighten2).Height(60); - stack.Item().SkipOnce().Background(Colors.Green.Lighten2).Height(40); + column.Item().ShowOnce().Background(Colors.Blue.Lighten2).Height(60); + column.Item().SkipOnce().Background(Colors.Green.Lighten2).Height(40); }); - page.Content().PaddingVertical(10).Stack(stack => + page.Content().PaddingVertical(10).Column(column => { - stack.Spacing(10); + column.Spacing(10); foreach (var _ in Enumerable.Range(0, 13)) - stack.Item().Background(Colors.Grey.Lighten2).Height(40); + column.Item().Background(Colors.Grey.Lighten2).Height(40); }); page.Footer().AlignCenter().Text(text => diff --git a/QuestPDF.Examples/ElementExamples.cs b/QuestPDF.Examples/ElementExamples.cs index e37423b..cdcbd3b 100644 --- a/QuestPDF.Examples/ElementExamples.cs +++ b/QuestPDF.Examples/ElementExamples.cs @@ -66,27 +66,27 @@ namespace QuestPDF.Examples container .Background("#FFF") .Padding(20) - .Stack(stack => + .Column(column => { - stack.Item() + column.Item() .PaddingBottom(10) .AlignCenter() .Text("This Row element is 700pt wide"); - stack.Item().Row(row => + column.Item().Row(row => { - row.ConstantColumn(100) + row.ConstantItem(100) .Background(Colors.Grey.Lighten1) .Padding(10) .ExtendVertical() .Text("This column is 100 pt wide"); - row.RelativeColumn() + row.RelativeItem() .Background(Colors.Grey.Lighten2) .Padding(10) .Text("This column takes 1/3 of the available space (200pt)"); - row.RelativeColumn(2) + row.RelativeItem(2) .Background(Colors.Grey.Lighten3) .Padding(10) .Text("This column takes 2/3 of the available space (400pt)"); @@ -109,15 +109,15 @@ namespace QuestPDF.Examples .Row(row => { row.Spacing(20); - row.RelativeColumn(2).Border(1).Background(Colors.Grey.Lighten1); - row.RelativeColumn(3).Border(1).Background(Colors.Grey.Lighten2); - row.RelativeColumn(4).Border(1).Background(Colors.Grey.Lighten3); + row.RelativeItem(2).Border(1).Background(Colors.Grey.Lighten1); + row.RelativeItem(3).Border(1).Background(Colors.Grey.Lighten2); + row.RelativeItem(4).Border(1).Background(Colors.Grey.Lighten3); }); }); } [Test] - public void Stack() + public void column() { RenderingTest .Create() @@ -127,13 +127,13 @@ namespace QuestPDF.Examples container .Background("#FFF") .Padding(15) - .Stack(stack => + .Column(column => { - stack.Spacing(15); + column.Spacing(15); - stack.Item().Background(Colors.Grey.Medium).Height(50); - stack.Item().Background(Colors.Grey.Lighten1).Height(100); - stack.Item().Background(Colors.Grey.Lighten2).Height(150); + column.Item().Background(Colors.Grey.Medium).Height(50); + column.Item().Background(Colors.Grey.Lighten1).Height(100); + column.Item().Background(Colors.Grey.Lighten2).Height(150); }); }); } @@ -267,12 +267,12 @@ namespace QuestPDF.Examples layers .PrimaryLayer() .Padding(25) - .Stack(stack => + .Column(column => { - stack.Spacing(5); + column.Spacing(5); foreach (var _ in Enumerable.Range(0, 7)) - stack.Item().Text(Placeholders.Sentence()); + column.Item().Text(Placeholders.Sentence()); }); // layer above the main content @@ -304,16 +304,16 @@ namespace QuestPDF.Examples // { // page.Header().PageNumber("Page {pdf:currentPage}"); // - // page.Content().Height(300).Stack(content => + // page.Content().Height(300).column(content => // { // content.Item().Height(200).Background(Colors.Grey.Lighten2); // - // content.Item().EnsureSpace(100).Stack(stack => + // content.Item().EnsureSpace(100).column(column => // { - // stack.Spacing(10); + // column.Spacing(10); // // foreach (var _ in Enumerable.Range(0, 4)) - // stack.Item().Height(50).Background(Colors.Green.Lighten1); + // column.Item().Height(50).Background(Colors.Green.Lighten1); // }); // }); // }); @@ -378,7 +378,7 @@ namespace QuestPDF.Examples .Row(row => { foreach (var color in colors) - row.RelativeColumn().Background(color); + row.RelativeItem().Background(color); }); }); } @@ -437,10 +437,10 @@ namespace QuestPDF.Examples { layers.Layer().Text("Something else"); - layers.PrimaryLayer().Stack(stack => + layers.PrimaryLayer().Column(column => { - stack.Item().PaddingTop(20).Text("Text 1"); - stack.Item().PaddingTop(40).Text("Text 2"); + column.Item().PaddingTop(20).Text("Text 1"); + column.Item().PaddingTop(40).Text("Text 2"); }); layers.Layer().Canvas((canvas, size) => @@ -507,7 +507,7 @@ namespace QuestPDF.Examples decoration .Content() - .Stack(stack => + .Column(column => { var scales = new[] { 0.8f, 0.9f, 1.1f, 1.2f }; @@ -519,7 +519,7 @@ namespace QuestPDF.Examples var fontStyle = TextStyle.Default.Size(16); - stack + column .Item() .Border(1) .Background(fontColor) @@ -708,14 +708,14 @@ namespace QuestPDF.Examples .Border(2) .Row(row => { - row.ConstantColumn(25) + row.ConstantItem(25) .Border(1) .RotateLeft() .AlignCenter() .AlignMiddle() .Text("Sample text"); - row.RelativeColumn().Border(1).Padding(5).Text(Placeholders.Paragraph()); + row.RelativeItem().Border(1).Padding(5).Text(Placeholders.Paragraph()); }); }); } @@ -731,11 +731,11 @@ namespace QuestPDF.Examples container .Padding(25) .PaddingLeft(75) - .Stack(stack => + .Column(column => { - stack.Item().Width(300).Height(150).Background(Colors.Blue.Lighten4); + column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten4); - stack + column .Item() // creates an infinite space for its child @@ -751,7 +751,7 @@ namespace QuestPDF.Examples .Background(Colors.Blue.Darken1); - stack.Item().Width(300).Height(150).Background(Colors.Blue.Lighten3); + column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten3); }); }); } @@ -766,13 +766,13 @@ namespace QuestPDF.Examples { container .Padding(25) - .Stack(stack => + .Column(column => { - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn().LabelCell("Label 1"); + row.RelativeItem().LabelCell("Label 1"); - row.RelativeColumn(3).Grid(grid => + row.RelativeItem(3).Grid(grid => { grid.Columns(3); @@ -784,11 +784,11 @@ namespace QuestPDF.Examples }); }); - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn().ValueCell().Text("Value 1"); + row.RelativeItem().ValueCell().Text("Value 1"); - row.RelativeColumn(3).Grid(grid => + row.RelativeItem(3).Grid(grid => { grid.Columns(3); @@ -800,10 +800,10 @@ namespace QuestPDF.Examples }); }); - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn().LabelCell("Label 6"); - row.RelativeColumn().ValueCell().Text("Value 6"); + row.RelativeItem().LabelCell("Label 6"); + row.RelativeItem().ValueCell().Text("Value 6"); }); }); }); diff --git a/QuestPDF.Examples/EnsureSpaceExample.cs b/QuestPDF.Examples/EnsureSpaceExample.cs index 0808774..0425f1b 100644 --- a/QuestPDF.Examples/EnsureSpaceExample.cs +++ b/QuestPDF.Examples/EnsureSpaceExample.cs @@ -25,15 +25,15 @@ namespace QuestPDF.Examples page.Header().Text("With ensure space", TextStyle.Default.SemiBold()); - page.Content().Stack(stack => + page.Content().Column(column => { - stack + column .Item() .ExtendHorizontal() .Height(75) .Background(Colors.Grey.Lighten2); - stack + column .Item() .EnsureSpace(100) .Text(Placeholders.LoremIpsum()); diff --git a/QuestPDF.Examples/FrameExample.cs b/QuestPDF.Examples/FrameExample.cs index 29cfa1d..e8f89b8 100644 --- a/QuestPDF.Examples/FrameExample.cs +++ b/QuestPDF.Examples/FrameExample.cs @@ -36,14 +36,14 @@ namespace QuestPDF.Examples container .Background("#FFF") .Padding(25) - .Stack(stack => + .Column(column => { for(var i = 1; i <= 4; i++) { - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(2).LabelCell(Placeholders.Label()); - row.RelativeColumn(3).ValueCell().Text(Placeholders.Paragraph()); + row.RelativeItem(2).LabelCell(Placeholders.Label()); + row.RelativeItem(3).ValueCell().Text(Placeholders.Paragraph()); }); } }); diff --git a/QuestPDF.Examples/ImageExamples.cs b/QuestPDF.Examples/ImageExamples.cs index fd0a599..b3bed24 100644 --- a/QuestPDF.Examples/ImageExamples.cs +++ b/QuestPDF.Examples/ImageExamples.cs @@ -19,17 +19,17 @@ namespace QuestPDF.Examples .ShowResults() .Render(page => { - page.Padding(25).Stack(stack => + page.Padding(25).Column(column => { - stack.Spacing(25); + column.Spacing(25); - stack.Item().Image("logo.png"); + column.Item().Image("logo.png"); var binaryData = File.ReadAllBytes("logo.png"); - stack.Item().Image(binaryData); + column.Item().Image(binaryData); using var stream = new FileStream("logo.png", FileMode.Open); - stack.Item().Image(stream); + column.Item().Image(stream); }); }); } diff --git a/QuestPDF.Examples/LineExamples.cs b/QuestPDF.Examples/LineExamples.cs new file mode 100644 index 0000000..f9ee753 --- /dev/null +++ b/QuestPDF.Examples/LineExamples.cs @@ -0,0 +1,50 @@ +using System.IO; +using NUnit.Framework; +using QuestPDF.Examples.Engine; +using QuestPDF.Fluent; +using QuestPDF.Helpers; + +namespace QuestPDF.Examples +{ + public class LineExamples + { + [Test] + public void LineHorizontal() + { + RenderingTest + .Create() + .PageSize(PageSizes.A5) + .ProducePdf() + .ShowResults() + .Render(container => + { + container.Padding(25).Column(column => + { + column.Item().Text("Above text"); + column.Item().PaddingVertical(10).LineHorizontal(1).LineColor(Colors.Blue.Accent1); + column.Item().Text("Below text"); + }); + }); + } + + [Test] + public void LineVertical() + { + RenderingTest + .Create() + .PageSize(PageSizes.A5) + .ProducePdf() + .ShowResults() + .Render(container => + { + container.Padding(25).Row(row => + { + row.Spacing(25); + // row.AutoItem().Text("Above text"); + // row.AutoItem().LineVertical(1).LineColor(Colors.Blue.Accent1); + // row.AutoItem().Text("Below text"); + }); + }); + } + } +} \ No newline at end of file diff --git a/QuestPDF.Examples/LoremPicsumExample.cs b/QuestPDF.Examples/LoremPicsumExample.cs index 3dca20c..e42417c 100644 --- a/QuestPDF.Examples/LoremPicsumExample.cs +++ b/QuestPDF.Examples/LoremPicsumExample.cs @@ -43,7 +43,7 @@ namespace QuestPDF.Examples container .Background("#FFF") .Padding(25) - .Stack(column => + .Column(column => { column.Spacing(10); diff --git a/QuestPDF.Examples/Padding.cs b/QuestPDF.Examples/Padding.cs index e20b71b..a544765 100644 --- a/QuestPDF.Examples/Padding.cs +++ b/QuestPDF.Examples/Padding.cs @@ -63,7 +63,7 @@ namespace QuestPDF.Examples .Render(container => { container - .Stack(column => + .Column(column => { column .Item() @@ -113,14 +113,14 @@ namespace QuestPDF.Examples .Render(container => { container - .Stack(column => + .Column(column => { column .Item() .Height(150) .Row(row => { - row.RelativeColumn() + row.RelativeItem() .Extend() .Background("FFF") @@ -128,7 +128,7 @@ namespace QuestPDF.Examples .Width(50) .Background("444"); - row.RelativeColumn() + row.RelativeItem() .Extend() .Background("BBB") @@ -142,7 +142,7 @@ namespace QuestPDF.Examples .Height(150) .Row(row => { - row.RelativeColumn() + row.RelativeItem() .Extend() .Background("BBB") @@ -150,7 +150,7 @@ namespace QuestPDF.Examples .Width(50) .Background("444"); - row.RelativeColumn() + row.RelativeItem() .Extend() .Background("BBB") diff --git a/QuestPDF.Examples/RowExamples.cs b/QuestPDF.Examples/RowExamples.cs index cd200b4..e63109c 100644 --- a/QuestPDF.Examples/RowExamples.cs +++ b/QuestPDF.Examples/RowExamples.cs @@ -9,7 +9,7 @@ namespace QuestPDF.Examples public class RowExamples { [Test] - public void ColumnTypes() + public void ItemTypes() { RenderingTest .Create() @@ -22,25 +22,24 @@ namespace QuestPDF.Examples .Padding(25) .MinimalBox() .Border(1) - .Stack(stack => + .Column(column => { - stack.Item().LabelCell("Total width: 600px"); + column.Item().LabelCell("Total width: 600px"); - stack.Item().Row(row => + column.Item().Row(row => { - row.ConstantColumn(150).ValueCell("150px"); - row.ConstantColumn(100).ValueCell("100px"); - row.RelativeColumn(4).ValueCell("200px"); - row.RelativeColumn(3).ValueCell("150px"); + row.ConstantItem(150).ValueCell("150px"); + row.ConstantItem(100).ValueCell("100px"); + row.RelativeItem(4).ValueCell("200px"); + row.RelativeItem(3).ValueCell("150px"); }); - stack.Item().Row(row => + column.Item().Row(row => { - row.ConstantColumn(100).ValueCell("100px"); - row.ConstantColumn(50).ValueCell("50px"); - row.Column(constantWidth: 100, relativeWidth: 4).ValueCell("350px"); - row.RelativeColumn(2).ValueCell("100px"); - row.RelativeColumn(1).ValueCell("50px"); + row.ConstantItem(100).ValueCell("100px"); + row.ConstantItem(50).ValueCell("50px"); + row.RelativeItem(2).ValueCell("100px"); + row.RelativeItem(1).ValueCell("50px"); }); }); }); @@ -63,17 +62,17 @@ namespace QuestPDF.Examples .Padding(25) .Row(row => { - row.RelativeColumn().Stack(stack => + row.RelativeItem().Column(column => { - stack.Item().ShowOnce().Element(CreateBox).Text("X"); - stack.Item().Element(CreateBox).Text("1"); - stack.Item().Element(CreateBox).Text("2"); + column.Item().ShowOnce().Element(CreateBox).Text("X"); + column.Item().Element(CreateBox).Text("1"); + column.Item().Element(CreateBox).Text("2"); }); - row.RelativeColumn().Stack(stack => + row.RelativeItem().Column(column => { - stack.Item().Element(CreateBox).Text("1"); - stack.Item().Element(CreateBox).Text("2"); + column.Item().Element(CreateBox).Text("1"); + column.Item().Element(CreateBox).Text("2"); }); }); }); diff --git a/QuestPDF.Examples/ScaleToFitExamples.cs b/QuestPDF.Examples/ScaleToFitExamples.cs index a5017d0..f1d714b 100644 --- a/QuestPDF.Examples/ScaleToFitExamples.cs +++ b/QuestPDF.Examples/ScaleToFitExamples.cs @@ -19,13 +19,13 @@ namespace QuestPDF.Examples .ShowResults() .Render(container => { - container.Padding(25).Stack(stack => + container.Padding(25).Column(column => { var text = Placeholders.Paragraph(); foreach (var i in Enumerable.Range(0, 16)) { - stack + column .Item() .MinimalBox() .Border(1) diff --git a/QuestPDF.Examples/ShowOnceExample.cs b/QuestPDF.Examples/ShowOnceExample.cs index 72e4727..8d88fe8 100644 --- a/QuestPDF.Examples/ShowOnceExample.cs +++ b/QuestPDF.Examples/ShowOnceExample.cs @@ -27,14 +27,14 @@ namespace QuestPDF.Examples page.Content().PaddingVertical(5).Row(row => { - row.RelativeColumn() + row.RelativeItem() .Background(Colors.Grey.Lighten2) .Border(1) .Padding(5) .ShowOnce() .Text(Placeholders.Label()); - row.RelativeColumn(2) + row.RelativeItem(2) .Border(1) .Padding(5) .Text(Placeholders.Paragraph()); diff --git a/QuestPDF.Examples/SkipOnceExample.cs b/QuestPDF.Examples/SkipOnceExample.cs index 8e73e9d..634fee5 100644 --- a/QuestPDF.Examples/SkipOnceExample.cs +++ b/QuestPDF.Examples/SkipOnceExample.cs @@ -23,10 +23,10 @@ namespace QuestPDF.Examples page.Size(PageSizes.A7.Landscape()); page.Background(Colors.White); - page.Header().Stack(stack => + page.Header().Column(column => { - stack.Item().ShowOnce().Text("This header is visible on the first page."); - stack.Item().SkipOnce().Text("This header is visible on the second page and all following."); + column.Item().ShowOnce().Text("This header is visible on the first page."); + column.Item().SkipOnce().Text("This header is visible on the second page and all following."); }); page.Content() diff --git a/QuestPDF.Examples/TextBenchmark.cs b/QuestPDF.Examples/TextBenchmark.cs index 301df11..4adaee9 100644 --- a/QuestPDF.Examples/TextBenchmark.cs +++ b/QuestPDF.Examples/TextBenchmark.cs @@ -117,16 +117,16 @@ namespace QuestPDF.Examples { decoration .Content() - .Stack(stack => + .Column(column => { - stack.Item().Element(Title); - stack.Item().PageBreak(); - stack.Item().Element(TableOfContents); - stack.Item().PageBreak(); + column.Item().Element(Title); + column.Item().PageBreak(); + column.Item().Element(TableOfContents); + column.Item().PageBreak(); - Chapters(stack); + Chapters(column); - stack.Item().Element(Acknowledgements); + column.Item().Element(Acknowledgements); }); decoration.Footer().Element(Footer); @@ -139,61 +139,61 @@ namespace QuestPDF.Examples .Extend() .PaddingBottom(200) .AlignBottom() - .Stack(stack => + .Column(column => { - stack.Item().Text("Quo Vadis", TextStyle.Default.Size(72).Bold().Color(Colors.Blue.Darken2)); - stack.Item().Text("Henryk Sienkiewicz", TextStyle.Default.Size(24).Color(Colors.Grey.Darken2)); + column.Item().Text("Quo Vadis", TextStyle.Default.Size(72).Bold().Color(Colors.Blue.Darken2)); + column.Item().Text("Henryk Sienkiewicz", TextStyle.Default.Size(24).Color(Colors.Grey.Darken2)); }); } void TableOfContents(IContainer container) { - container.Stack(stack => + container.Column(column => { - SectionTitle(stack, "Spis treści"); + SectionTitle(column, "Spis treści"); foreach (var chapter in chapters) { - stack.Item().InternalLink(chapter.Title).Row(row => + column.Item().InternalLink(chapter.Title).Row(row => { - row.RelativeColumn().Text(chapter.Title, normalStyle); - row.ConstantColumn(100).AlignRight().Text(text => text.PageNumberOfLocation(chapter.Title, normalStyle)); + row.RelativeItem().Text(chapter.Title, normalStyle); + row.ConstantItem(100).AlignRight().Text(text => text.PageNumberOfLocation(chapter.Title, normalStyle)); }); } }); } - void Chapters(StackDescriptor stack) + void Chapters(ColumnDescriptor column) { foreach (var chapter in chapters) { - stack.Item().Element(container => Chapter(container, chapter.Title, chapter.Content)); + column.Item().Element(container => Chapter(container, chapter.Title, chapter.Content)); } } void Chapter(IContainer container, string title, string content) { - container.Stack(stack => + container.Column(column => { - SectionTitle(stack, title); + SectionTitle(column, title); - stack.Item().Text(text => + column.Item().Text(text => { text.ParagraphSpacing(5); text.Span(content, normalStyle); }); - stack.Item().PageBreak(); + column.Item().PageBreak(); }); } void Acknowledgements(IContainer container) { - container.Stack(stack => + container.Column(column => { - SectionTitle(stack, "Podziękowania"); + SectionTitle(column, "Podziękowania"); - stack.Item().Text(text => + column.Item().Text(text => { text.DefaultTextStyle(normalStyle); @@ -204,10 +204,10 @@ namespace QuestPDF.Examples }); } - void SectionTitle(StackDescriptor stack, string text) + void SectionTitle(ColumnDescriptor column, string text) { - stack.Item().Location(text).Text(text, subtitleStyle); - stack.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal(); + column.Item().Location(text).Text(text, subtitleStyle); + column.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal(); } void Footer(IContainer container) diff --git a/QuestPDF.Examples/TextExamples.cs b/QuestPDF.Examples/TextExamples.cs index dfe8d35..ef12e96 100644 --- a/QuestPDF.Examples/TextExamples.cs +++ b/QuestPDF.Examples/TextExamples.cs @@ -126,7 +126,7 @@ namespace QuestPDF.Examples } [Test] - public void TextStack() + public void Textcolumn() { RenderingTest .Create() diff --git a/QuestPDF.ReportSample/Layouts/DifferentHeadersTemplate.cs b/QuestPDF.ReportSample/Layouts/DifferentHeadersTemplate.cs index 7f54bdb..e67fb58 100644 --- a/QuestPDF.ReportSample/Layouts/DifferentHeadersTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/DifferentHeadersTemplate.cs @@ -26,58 +26,58 @@ namespace QuestPDF.ReportSample.Layouts private void ComposeHeader(IContainer container) { - container.Background(Colors.Grey.Lighten3).Border(1).Stack(stack => + container.Background(Colors.Grey.Lighten3).Border(1).Column(column => { - stack.Item().ShowOnce().Padding(5).AlignMiddle().Row(row => + column.Item().ShowOnce().Padding(5).AlignMiddle().Row(row => { - row.RelativeColumn(2).AlignMiddle().Text("PRIMARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold()); - row.RelativeColumn(1).AlignRight().MinimalBox().AlignMiddle().Background(Colors.Blue.Darken2).Padding(30); + row.RelativeItem(2).AlignMiddle().Text("PRIMARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold()); + row.RelativeItem(1).AlignRight().MinimalBox().AlignMiddle().Background(Colors.Blue.Darken2).Padding(30); }); - stack.Item().SkipOnce().Padding(5).Row(row => + column.Item().SkipOnce().Padding(5).Row(row => { - row.RelativeColumn(2).Text("SECONDARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold()); - row.RelativeColumn(1).AlignRight().MinimalBox().Background(Colors.Blue.Lighten4).Padding(15); + row.RelativeItem(2).Text("SECONDARY HEADER", TextStyle.Default.Color(Colors.Grey.Darken3).Size(30).Bold()); + row.RelativeItem(1).AlignRight().MinimalBox().Background(Colors.Blue.Lighten4).Padding(15); }); }); } private void ComposeContent(IContainer container) { - container.Stack(stack => + container.Column(column => { - stack.Item().PaddingVertical(80).Text("First"); - stack.Item().PageBreak(); - stack.Item().PaddingVertical(80).Text("Second"); - stack.Item().PageBreak(); - stack.Item().PaddingVertical(80).Text("Third"); - stack.Item().PageBreak(); + column.Item().PaddingVertical(80).Text("First"); + column.Item().PageBreak(); + column.Item().PaddingVertical(80).Text("Second"); + column.Item().PageBreak(); + column.Item().PaddingVertical(80).Text("Third"); + column.Item().PageBreak(); }); } private void ComposeFooter(IContainer container) { - container.Background(Colors.Grey.Lighten3).Stack(stack => + container.Background(Colors.Grey.Lighten3).Column(column => { - stack.Item().ShowOnce().Background(Colors.Grey.Lighten3).Row(row => + column.Item().ShowOnce().Background(Colors.Grey.Lighten3).Row(row => { - row.RelativeColumn().Text(x => + row.RelativeItem().Text(x => { x.CurrentPageNumber(); x.Span(" / "); x.TotalPages(); }); - row.RelativeColumn().AlignRight().Text("Footer for header"); + row.RelativeItem().AlignRight().Text("Footer for header"); }); - stack.Item().SkipOnce().Background(Colors.Grey.Lighten3).Row(row => + column.Item().SkipOnce().Background(Colors.Grey.Lighten3).Row(row => { - row.RelativeColumn().Text(x => + row.RelativeItem().Text(x => { x.CurrentPageNumber(); x.Span(" / "); x.TotalPages(); }); - row.RelativeColumn().AlignRight().Text("Footer for every page except header"); + row.RelativeItem().AlignRight().Text("Footer for every page except header"); }); }); } diff --git a/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs b/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs index d8fa483..f578e95 100644 --- a/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs @@ -17,11 +17,11 @@ namespace QuestPDF.ReportSample.Layouts { container .ShowEntire() - .Stack(stack => + .Column(column => { - stack.Spacing(5); - stack.Item().Element(PhotoWithMaps); - stack.Item().Element(PhotoDetails); + column.Spacing(5); + column.Item().Element(PhotoWithMaps); + column.Item().Element(PhotoDetails); }); } @@ -30,14 +30,14 @@ namespace QuestPDF.ReportSample.Layouts container .Row(row => { - row.RelativeColumn(2).AspectRatio(4 / 3f).Component(); + row.RelativeItem(2).AspectRatio(4 / 3f).Component(); - row.RelativeColumn().PaddingLeft(5).Stack(stack => + row.RelativeItem().PaddingLeft(5).Column(column => { - stack.Spacing(7f); + column.Spacing(7f); - stack.Item().AspectRatio(4 / 3f).Component(); - stack.Item().AspectRatio(4 / 3f).Component(); + column.Item().AspectRatio(4 / 3f).Component(); + column.Item().AspectRatio(4 / 3f).Component(); }); }); } diff --git a/QuestPDF.ReportSample/Layouts/SectionTemplate.cs b/QuestPDF.ReportSample/Layouts/SectionTemplate.cs index fa1eb5e..361277a 100644 --- a/QuestPDF.ReportSample/Layouts/SectionTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/SectionTemplate.cs @@ -25,21 +25,21 @@ namespace QuestPDF.ReportSample.Layouts .PaddingBottom(5) .Text(Model.Title, Typography.Headline); - decoration.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Stack(stack => + decoration.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Column(column => { foreach (var part in Model.Parts) { - stack.Item().EnsureSpace(25).Row(row => + column.Item().EnsureSpace(25).Row(row => { - row.ConstantColumn(150).LabelCell().Text(part.Label); - var frame = row.RelativeColumn().ValueCell(); + row.ConstantItem(150).LabelCell().Text(part.Label); + var frame = row.RelativeItem().ValueCell(); if (part is ReportSectionText text) frame.ShowEntire().Text(text.Text); - + if (part is ReportSectionMap map) frame.Element(x => MapElement(x, map)); - + if (part is ReportSectionPhotos photos) frame.Element(x => PhotosElement(x, photos)); }); @@ -56,12 +56,12 @@ namespace QuestPDF.ReportSample.Layouts return; } - container.ShowEntire().Stack(stack => + container.ShowEntire().Column(column => { - stack.Spacing(5); + column.Spacing(5); - stack.Item().MaxWidth(250).AspectRatio(4 / 3f).Component(); - stack.Item().Text(model.Location.Format()); + column.Item().MaxWidth(250).AspectRatio(4 / 3f).Component(); + column.Item().Text(model.Location.Format()); }); } diff --git a/QuestPDF.ReportSample/Layouts/StandardReport.cs b/QuestPDF.ReportSample/Layouts/StandardReport.cs index 25fac2a..2bba69a 100644 --- a/QuestPDF.ReportSample/Layouts/StandardReport.cs +++ b/QuestPDF.ReportSample/Layouts/StandardReport.cs @@ -48,19 +48,19 @@ namespace QuestPDF.ReportSample.Layouts private void ComposeHeader(IContainer container) { - container.Stack(stack => + container.Column(column => { - stack.Item().Row(row => + column.Item().Row(row => { row.Spacing(50); - row.RelativeColumn().PaddingTop(-10).Text(Model.Title, Typography.Title); - row.ConstantColumn(90).ExternalLink("https://www.questpdf.com").MaxHeight(30).Component(); + row.RelativeItem().PaddingTop(-10).Text(Model.Title, Typography.Title); + row.ConstantItem(90).ExternalLink("https://www.questpdf.com").MaxHeight(30).Component(); }); - stack.Item().ShowOnce().PaddingVertical(15).Border(1f).BorderColor(Colors.Grey.Lighten1).ExtendHorizontal(); + column.Item().ShowOnce().PaddingVertical(15).Border(1f).BorderColor(Colors.Grey.Lighten1).ExtendHorizontal(); - stack.Item().ShowOnce().Grid(grid => + column.Item().ShowOnce().Grid(grid => { grid.Columns(2); grid.Spacing(5); @@ -79,22 +79,22 @@ namespace QuestPDF.ReportSample.Layouts void ComposeContent(IContainer container) { - container.PaddingVertical(20).Stack(stack => + container.PaddingVertical(20).Column(column => { - stack.Spacing(20); - - stack.Item().Component(new TableOfContentsTemplate(Model.Sections)); + column.Spacing(20); - stack.Item().PageBreak(); + column.Item().Component(new TableOfContentsTemplate(Model.Sections)); + + column.Item().PageBreak(); foreach (var section in Model.Sections) - stack.Item().Location(section.Title).Component(new SectionTemplate(section)); - - stack.Item().PageBreak(); - stack.Item().Location("Photos"); + column.Item().Location(section.Title).Component(new SectionTemplate(section)); + + column.Item().PageBreak(); + column.Item().Location("Photos"); foreach (var photo in Model.Photos) - stack.Item().Component(new PhotoTemplate(photo)); + column.Item().Component(new PhotoTemplate(photo)); }); } } diff --git a/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs b/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs index 64ff8f2..a3cb715 100644 --- a/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs @@ -23,14 +23,14 @@ namespace QuestPDF.ReportSample.Layouts .PaddingBottom(5) .Text("Table of contents", Typography.Headline); - decoration.Content().Stack(stack => + decoration.Content().Column(column => { - stack.Spacing(5); + column.Spacing(5); for (var i = 0; i < Sections.Count; i++) - stack.Item().Element(c => DrawLink(c, i+1, Sections[i].Title)); + column.Item().Element(c => DrawLink(c, i+1, Sections[i].Title)); - stack.Item().Element(c => DrawLink(c, Sections.Count+1, "Photos")); + column.Item().Element(c => DrawLink(c, Sections.Count+1, "Photos")); }); }); } @@ -41,9 +41,9 @@ namespace QuestPDF.ReportSample.Layouts .InternalLink(locationName) .Row(row => { - row.ConstantColumn(25).Text($"{number}."); - row.RelativeColumn().Text(locationName); - row.ConstantColumn(150).AlignRight().Text(text => text.PageNumberOfLocation(locationName)); + row.ConstantItem(25).Text($"{number}."); + row.RelativeItem().Text(locationName); + row.ConstantItem(150).AlignRight().Text(text => text.PageNumberOfLocation(locationName)); }); } } diff --git a/QuestPDF.ReportSample/Tests.cs b/QuestPDF.ReportSample/Tests.cs index 96b2f7f..111df78 100644 --- a/QuestPDF.ReportSample/Tests.cs +++ b/QuestPDF.ReportSample/Tests.cs @@ -24,7 +24,7 @@ namespace QuestPDF.ReportSample [Test] public void GenerateAndShowPdf() { - ImagePlaceholder.Solid = true; + //ImagePlaceholder.Solid = true; var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf"); Report.GeneratePdf(path); diff --git a/QuestPDF.UnitTests/GridTests.cs b/QuestPDF.UnitTests/GridTests.cs index e55d08e..54149a1 100644 --- a/QuestPDF.UnitTests/GridTests.cs +++ b/QuestPDF.UnitTests/GridTests.cs @@ -39,26 +39,26 @@ namespace QuestPDF.UnitTests // assert var expected = new Container(); - expected.Stack(stack => + expected.Column(column => { - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(6).Element(childA); - row.RelativeColumn(4).Element(childB); - row.RelativeColumn(2); + row.RelativeItem(6).Element(childA); + row.RelativeItem(4).Element(childB); + row.RelativeItem(2); }); - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(4).Element(childC); - row.RelativeColumn(2).Element(childD); - row.RelativeColumn(6); + row.RelativeItem(4).Element(childC); + row.RelativeItem(2).Element(childD); + row.RelativeItem(6); }); - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(8).Element(childE); - row.RelativeColumn(4); + row.RelativeItem(8).Element(childE); + row.RelativeItem(4); }); }); @@ -93,29 +93,29 @@ namespace QuestPDF.UnitTests // assert var expected = new Container(); - expected.Stack(stack => + expected.Column(column => { - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(1); - row.RelativeColumn(6).Element(childA); - row.RelativeColumn(4).Element(childB); - row.RelativeColumn(1); + row.RelativeItem(1); + row.RelativeItem(6).Element(childA); + row.RelativeItem(4).Element(childB); + row.RelativeItem(1); }); - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(3); - row.RelativeColumn(4).Element(childC); - row.RelativeColumn(2).Element(childD); - row.RelativeColumn(3); + row.RelativeItem(3); + row.RelativeItem(4).Element(childC); + row.RelativeItem(2).Element(childD); + row.RelativeItem(3); }); - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(2); - row.RelativeColumn(8).Element(childE); - row.RelativeColumn(2); + row.RelativeItem(2); + row.RelativeItem(8).Element(childE); + row.RelativeItem(2); }); }); @@ -150,26 +150,26 @@ namespace QuestPDF.UnitTests // assert var expected = new Container(); - expected.Stack(stack => + expected.Column(column => { - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(2); - row.RelativeColumn(6).Element(childA); - row.RelativeColumn(4).Element(childB); + row.RelativeItem(2); + row.RelativeItem(6).Element(childA); + row.RelativeItem(4).Element(childB); }); - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(6); - row.RelativeColumn(4).Element(childC); - row.RelativeColumn(2).Element(childD); + row.RelativeItem(6); + row.RelativeItem(4).Element(childC); + row.RelativeItem(2).Element(childD); }); - stack.Item().Row(row => + column.Item().Row(row => { - row.RelativeColumn(4); - row.RelativeColumn(8).Element(childE); + row.RelativeItem(4); + row.RelativeItem(8).Element(childE); }); }); @@ -210,36 +210,36 @@ namespace QuestPDF.UnitTests // assert var expected = new Container(); - expected.Stack(stack => + expected.Column(column => { - stack.Spacing(20); + column.Spacing(20); - stack.Item().Row(row => + column.Item().Row(row => { row.Spacing(30); - row.RelativeColumn(3); - row.RelativeColumn(5).Element(childA); - row.RelativeColumn(5).Element(childB); - row.RelativeColumn(3); + row.RelativeItem(3); + row.RelativeItem(5).Element(childA); + row.RelativeItem(5).Element(childB); + row.RelativeItem(3); }); - stack.Item().Row(row => + column.Item().Row(row => { row.Spacing(30); - row.RelativeColumn(3); - row.RelativeColumn(10).Element(childC); - row.RelativeColumn(3); + row.RelativeItem(3); + row.RelativeItem(10).Element(childC); + row.RelativeItem(3); }); - stack.Item().Row(row => + column.Item().Row(row => { row.Spacing(30); - row.RelativeColumn(2); - row.RelativeColumn(12).Element(childD); - row.RelativeColumn(2); + row.RelativeItem(2); + row.RelativeItem(12).Element(childD); + row.RelativeItem(2); }); }); diff --git a/QuestPDF.UnitTests/RowTests.cs b/QuestPDF.UnitTests/RowTests.cs index fc1db47..c2d9925 100644 --- a/QuestPDF.UnitTests/RowTests.cs +++ b/QuestPDF.UnitTests/RowTests.cs @@ -132,11 +132,11 @@ namespace QuestPDF.UnitTests { row.Spacing(spacing); - row.ConstantColumn(150).Element(childA); - row.ConstantColumn(250).Element(childB); - row.RelativeColumn(1).Element(childC); - row.RelativeColumn(2).Element(childD); - row.RelativeColumn(3).Element(childE); + row.ConstantItem(150).Element(childA); + row.ConstantItem(250).Element(childB); + row.RelativeItem(1).Element(childC); + row.RelativeItem(2).Element(childD); + row.RelativeItem(3).Element(childE); }); // assert @@ -146,11 +146,11 @@ namespace QuestPDF.UnitTests { row.Spacing(spacing); - row.ConstantColumn(150).Element(childA); - row.ConstantColumn(250).Element(childB); - row.ConstantColumn(100).Element(childC); - row.ConstantColumn(200).Element(childD); - row.ConstantColumn(300).Element(childE); + row.ConstantItem(150).Element(childA); + row.ConstantItem(250).Element(childB); + row.ConstantItem(100).Element(childC); + row.ConstantItem(200).Element(childD); + row.ConstantItem(300).Element(childE); }); TestPlan.CompareOperations(value, expected, availableSpace); @@ -176,11 +176,11 @@ namespace QuestPDF.UnitTests { row.Spacing(spacing); - row.ConstantColumn(150).Element(childA); - row.ConstantColumn(200).Element(childB); - row.ConstantColumn(250).Element(childC); - row.RelativeColumn(2).Element(childD); - row.RelativeColumn(3).Element(childE); + row.ConstantItem(150).Element(childA); + row.ConstantItem(200).Element(childB); + row.ConstantItem(250).Element(childC); + row.RelativeItem(2).Element(childD); + row.RelativeItem(3).Element(childE); }); // assert diff --git a/QuestPDF.UnitTests/StackTests.cs b/QuestPDF.UnitTests/StackTests.cs index 58218bb..bbc1058 100644 --- a/QuestPDF.UnitTests/StackTests.cs +++ b/QuestPDF.UnitTests/StackTests.cs @@ -8,7 +8,7 @@ using QuestPDF.UnitTests.TestEngine; namespace QuestPDF.UnitTests { [TestFixture] - public class StackTests + public class columnTests { #region Measure @@ -16,7 +16,7 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsWrap_WhenFirstChildWraps() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -30,7 +30,7 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsPartialRender_WhenFirstChildReturnsPartialRender() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -44,7 +44,7 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsPartialRender_WhenSecondChildWraps() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -59,7 +59,7 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsPartialRender_WhenSecondChildReturnsPartialRender() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -74,7 +74,7 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsFullRender_WhenSecondChildReturnsFullRender() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -89,7 +89,7 @@ namespace QuestPDF.UnitTests public void Measure_UsesEmpty_WhenFirstChildIsRendered() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second"), @@ -109,7 +109,7 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildWraps() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -123,7 +123,7 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildPartiallyRenders() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -138,7 +138,7 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildFullyRenders_AndSecondChildWraps() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -154,7 +154,7 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildFullyRenders_AndSecondChildPartiallyRenders() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -173,7 +173,7 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildFullyRenders_AndSecondChildFullyRenders() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second") @@ -192,7 +192,7 @@ namespace QuestPDF.UnitTests public void Draw_UsesEmpty_WhenFirstChildIsRendered() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second"), @@ -204,7 +204,7 @@ namespace QuestPDF.UnitTests .ExpectCanvasTranslate(0, 0) .ExpectChildDraw("second", new Size(400, 300)) .ExpectCanvasTranslate(0, 0) - .CheckState(x => x.IsFirstRendered) + .CheckState(x => x.IsFirstRendered) .CheckDrawResult(); } @@ -212,7 +212,7 @@ namespace QuestPDF.UnitTests public void Draw_TogglesFirstRenderedFlag_WhenSecondFullyRenders() { TestPlan - .For(x => new BinaryStack + .For(x => new Binarycolumn { First = x.CreateChild("first"), Second = x.CreateChild("second"), @@ -225,7 +225,7 @@ namespace QuestPDF.UnitTests .ExpectChildDraw("second", new Size(400, 300)) .ExpectCanvasTranslate(0, 0) .CheckDrawResult() - .CheckState(x => !x.IsFirstRendered); + .CheckState(x => !x.IsFirstRendered); } #endregion @@ -247,15 +247,15 @@ namespace QuestPDF.UnitTests // act var structure = new Container(); - structure.Stack(stack => + structure.Column(column => { - stack.Spacing(spacing); + column.Spacing(spacing); - stack.Item().Element(childA); - stack.Item().Element(childB); - stack.Item().Element(childC); - stack.Item().Element(childD); - stack.Item().Element(childE); + column.Item().Element(childA); + column.Item().Element(childB); + column.Item().Element(childC); + column.Item().Element(childD); + column.Item().Element(childE); }); // assert @@ -263,9 +263,9 @@ namespace QuestPDF.UnitTests { Bottom = -spacing, - Child = new BinaryStack + Child = new Binarycolumn { - First = new BinaryStack + First = new Binarycolumn { First = new Padding { @@ -278,14 +278,14 @@ namespace QuestPDF.UnitTests Child = childB } }, - Second = new BinaryStack + Second = new Binarycolumn { First = new Padding { Bottom = spacing, Child = childC }, - Second = new BinaryStack + Second = new Binarycolumn { First = new Padding { diff --git a/QuestPDF/Drawing/DocumentContainer.cs b/QuestPDF/Drawing/DocumentContainer.cs index e813839..18a8cc9 100644 --- a/QuestPDF/Drawing/DocumentContainer.cs +++ b/QuestPDF/Drawing/DocumentContainer.cs @@ -16,13 +16,13 @@ namespace QuestPDF.Drawing var container = new Container(); container - .Stack(stack => + .Column(column => { Pages .SelectMany(x => new List() { - () => stack.Item().PageBreak(), - () => stack.Item().Component(x) + () => column.Item().PageBreak(), + () => column.Item().Component(x) }) .Skip(1) .ToList() diff --git a/QuestPDF/Elements/Column.cs b/QuestPDF/Elements/Column.cs new file mode 100644 index 0000000..8fad0f1 --- /dev/null +++ b/QuestPDF/Elements/Column.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using QuestPDF.Drawing; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Elements +{ + internal class ColumnItem : Container + { + public bool IsRendered { get; set; } + } + + internal class ColumnItemRenderingCommand + { + public ColumnItem ColumnItem { get; set; } + public SpacePlan Measurement { get; set; } + public Size Size { get; set; } + public Position Offset { get; set; } + } + + internal class Column : Element, ICacheable, IStateResettable + { + internal List Items { get; } = new(); + internal float Spacing { get; set; } + + public void ResetState() + { + Items.ForEach(x => x.IsRendered = false); + } + + internal override IEnumerable GetChildren() + { + return Items; + } + + internal override void CreateProxy(Func create) + { + Items.ForEach(x => x.Child = create(x.Child)); + } + + internal override SpacePlan Measure(Size availableSpace) + { + var renderingCommands = PlanLayout(availableSpace); + + if (!renderingCommands.Any()) + return SpacePlan.Wrap(); + + var width = renderingCommands.Max(x => x.Size.Width); + var height = renderingCommands.Last().Offset.Y + renderingCommands.Last().Size.Height; + var size = new Size(width, height); + + if (width > availableSpace.Width + Size.Epsilon || height > availableSpace.Height + Size.Epsilon) + return SpacePlan.Wrap(); + + var totalRenderedItems = Items.Count(x => x.IsRendered) + renderingCommands.Count(x => x.Measurement.Type == SpacePlanType.FullRender); + var willBeFullyRendered = totalRenderedItems == Items.Count; + + return willBeFullyRendered + ? SpacePlan.FullRender(size) + : SpacePlan.PartialRender(size); + } + + internal override void Draw(Size availableSpace) + { + var renderingCommands = PlanLayout(availableSpace); + + foreach (var command in renderingCommands) + { + if (command.Measurement.Type == SpacePlanType.FullRender) + command.ColumnItem.IsRendered = true; + + Canvas.Translate(command.Offset); + command.ColumnItem.Draw(command.Size); + Canvas.Translate(command.Offset.Reverse()); + } + + if (Items.All(x => x.IsRendered)) + ResetState(); + } + + private ICollection PlanLayout(Size availableSpace) + { + var topOffset = 0f; + var commands = new List(); + + foreach (var item in Items) + { + if (item.IsRendered) + continue; + + var itemSpace = new Size(availableSpace.Width, availableSpace.Height - topOffset); + var measurement = item.Measure(itemSpace); + + if (measurement.Type == SpacePlanType.Wrap) + break; + + commands.Add(new ColumnItemRenderingCommand + { + ColumnItem = item, + Size = measurement, + Measurement = measurement, + Offset = new Position(0, topOffset) + }); + + if (measurement.Type == SpacePlanType.PartialRender) + break; + + topOffset += measurement.Height + Spacing; + } + + var targetWidth = commands.Select(x => x.Size.Width).DefaultIfEmpty(0).Max(); + commands.ForEach(x => x.Size = new Size(targetWidth, x.Size.Height)); + + return commands; + } + } +} \ No newline at end of file diff --git a/QuestPDF/Elements/Decoration.cs b/QuestPDF/Elements/Decoration.cs index 39959f4..7b2fcd7 100644 --- a/QuestPDF/Elements/Decoration.cs +++ b/QuestPDF/Elements/Decoration.cs @@ -1,98 +1,102 @@ using System; using System.Collections.Generic; +using System.Linq; using QuestPDF.Drawing; using QuestPDF.Fluent; using QuestPDF.Infrastructure; namespace QuestPDF.Elements { - internal enum DecorationType + internal class DecorationItemRenderingCommand { - Prepend, - Append + public Element Element { get; set; } + public SpacePlan Measurement { get; set; } + public Size Size { get; set; } + public Position Offset { get; set; } } - internal class BinaryDecoration : Element, ICacheable + internal class Decoration : Element, ICacheable { - public Element DecorationElement { get; set; } = Empty.Instance; - public Element ContentElement { get; set; } = Empty.Instance; - public DecorationType Type { get; set; } + internal Element Header { get; set; } = new Empty(); + internal Element Content { get; set; } = new Empty(); + internal Element Footer { get; set; } = new Empty(); internal override IEnumerable GetChildren() { - yield return DecorationElement; - yield return ContentElement; + yield return Header; + yield return Content; + yield return Footer; } - - internal override void CreateProxy(Func create) + + internal override void CreateProxy(Func create) { - DecorationElement = create(DecorationElement); - ContentElement = create(ContentElement); + Header = create(Header); + Content = create(Content); + Footer = create(Footer); } internal override SpacePlan Measure(Size availableSpace) { - var decorationMeasure = DecorationElement.Measure(availableSpace); - - if (decorationMeasure.Type == SpacePlanType.Wrap || decorationMeasure.Type == SpacePlanType.PartialRender) + var renderingCommands = PlanLayout(availableSpace); + + if (renderingCommands.Any(x => x.Measurement.Type == SpacePlanType.Wrap)) return SpacePlan.Wrap(); - var decorationSize = decorationMeasure; - var contentMeasure = ContentElement.Measure(new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height)); + var width = renderingCommands.Max(x => x.Size.Width); + var height = renderingCommands.Sum(x => x.Size.Height); + var size = new Size(width, height); - if (contentMeasure.Type == SpacePlanType.Wrap) + if (width > availableSpace.Width + Size.Epsilon || height > availableSpace.Height + Size.Epsilon) return SpacePlan.Wrap(); + + var willBeFullyRendered = renderingCommands.All(x => x.Measurement.Type == SpacePlanType.FullRender); - var contentSize = contentMeasure; - var resultSize = new Size(availableSpace.Width, decorationSize.Height + contentSize.Height); - - if (contentSize.Type == SpacePlanType.PartialRender) - return SpacePlan.PartialRender(resultSize); - - if (contentSize.Type == SpacePlanType.FullRender) - return SpacePlan.FullRender(resultSize); - - throw new NotSupportedException(); + return willBeFullyRendered + ? SpacePlan.FullRender(size) + : SpacePlan.PartialRender(size); } internal override void Draw(Size availableSpace) { - var decorationSize = DecorationElement.Measure(availableSpace); - var contentSize = new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height); - - var translateHeight = Type == DecorationType.Prepend ? decorationSize.Height : contentSize.Height; - Action drawDecoration = () => DecorationElement?.Draw(new Size(availableSpace.Width, decorationSize.Height)); - Action drawContent = () => ContentElement?.Draw(new Size (availableSpace.Width, contentSize.Height)); - - var first = Type == DecorationType.Prepend ? drawDecoration : drawContent; - var second = Type == DecorationType.Prepend ? drawContent : drawDecoration; - - first(); - Canvas.Translate(new Position(0, translateHeight)); - second(); - Canvas.Translate(new Position(0, -translateHeight)); - } - } - - internal class Decoration : IComponent - { - public Element Header { get; set; } = Empty.Instance; - public Element Content { get; set; } = Empty.Instance; - public Element Footer { get; set; } = Empty.Instance; - - public void Compose(IContainer container) - { - container.Element(new BinaryDecoration + foreach (var command in PlanLayout(availableSpace)) { - Type = DecorationType.Prepend, - DecorationElement = Header, - ContentElement = new BinaryDecoration - { - Type = DecorationType.Append, - ContentElement = Content, - DecorationElement = Footer - } - }); + Canvas.Translate(command.Offset); + command.Element.Draw(command.Size); + Canvas.Translate(command.Offset.Reverse()); + } + } + + private IEnumerable PlanLayout(Size availableSpace) + { + var headerMeasurement = Header.Measure(availableSpace); + var footerMeasurement = Footer.Measure(availableSpace); + + var contentSpace = new Size(availableSpace.Width, availableSpace.Height - headerMeasurement.Height - footerMeasurement.Height); + var contentMeasurement = Content.Measure(contentSpace); + + yield return new DecorationItemRenderingCommand + { + Element = Header, + Measurement = headerMeasurement, + Size = new Size(availableSpace.Width, headerMeasurement.Height), + Offset = Position.Zero + }; + + yield return new DecorationItemRenderingCommand + { + Element = Content, + Measurement = contentMeasurement, + Size = new Size(availableSpace.Width, contentMeasurement.Height), + Offset = new Position(0, headerMeasurement.Height) + }; + + yield return new DecorationItemRenderingCommand + { + Element = Footer, + Measurement = footerMeasurement, + Size = new Size(availableSpace.Width, footerMeasurement.Height), + Offset = new Position(0, headerMeasurement.Height + contentMeasurement.Height) + }; } } } \ No newline at end of file diff --git a/QuestPDF/Elements/DecorationOld.cs b/QuestPDF/Elements/DecorationOld.cs new file mode 100644 index 0000000..c41c8c7 --- /dev/null +++ b/QuestPDF/Elements/DecorationOld.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using QuestPDF.Drawing; +using QuestPDF.Fluent; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Elements +{ + // TODO: remove + internal enum DecorationType + { + Prepend, + Append + } + + // TODO: remove + internal class BinaryDecoration : Element, ICacheable + { + public Element DecorationElement { get; set; } = Empty.Instance; + public Element ContentElement { get; set; } = Empty.Instance; + public DecorationType Type { get; set; } + + internal override IEnumerable GetChildren() + { + yield return DecorationElement; + yield return ContentElement; + } + + internal override void CreateProxy(Func create) + { + DecorationElement = create(DecorationElement); + ContentElement = create(ContentElement); + } + + internal override SpacePlan Measure(Size availableSpace) + { + var decorationMeasure = DecorationElement.Measure(availableSpace); + + if (decorationMeasure.Type == SpacePlanType.Wrap || decorationMeasure.Type == SpacePlanType.PartialRender) + return SpacePlan.Wrap(); + + var decorationSize = decorationMeasure; + var contentMeasure = ContentElement.Measure(new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height)); + + if (contentMeasure.Type == SpacePlanType.Wrap) + return SpacePlan.Wrap(); + + var contentSize = contentMeasure; + var resultSize = new Size(availableSpace.Width, decorationSize.Height + contentSize.Height); + + if (contentSize.Type == SpacePlanType.PartialRender) + return SpacePlan.PartialRender(resultSize); + + if (contentSize.Type == SpacePlanType.FullRender) + return SpacePlan.FullRender(resultSize); + + throw new NotSupportedException(); + } + + internal override void Draw(Size availableSpace) + { + var decorationSize = DecorationElement.Measure(availableSpace); + var contentSize = new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height); + + var translateHeight = Type == DecorationType.Prepend ? decorationSize.Height : contentSize.Height; + Action drawDecoration = () => DecorationElement?.Draw(new Size(availableSpace.Width, decorationSize.Height)); + Action drawContent = () => ContentElement?.Draw(new Size (availableSpace.Width, contentSize.Height)); + + var first = Type == DecorationType.Prepend ? drawDecoration : drawContent; + var second = Type == DecorationType.Prepend ? drawContent : drawDecoration; + + first(); + Canvas.Translate(new Position(0, translateHeight)); + second(); + Canvas.Translate(new Position(0, -translateHeight)); + } + } + + // TODO: remove + internal class DecorationOld : IComponent + { + public Element Header { get; set; } = Empty.Instance; + public Element Content { get; set; } = Empty.Instance; + public Element Footer { get; set; } = Empty.Instance; + + public void Compose(IContainer container) + { + container.Element(new BinaryDecoration + { + Type = DecorationType.Prepend, + DecorationElement = Header, + ContentElement = new BinaryDecoration + { + Type = DecorationType.Append, + ContentElement = Content, + DecorationElement = Footer + } + }); + } + } +} \ No newline at end of file diff --git a/QuestPDF/Elements/Grid.cs b/QuestPDF/Elements/Grid.cs index 7014bf6..a1d80e1 100644 --- a/QuestPDF/Elements/Grid.cs +++ b/QuestPDF/Elements/Grid.cs @@ -27,12 +27,12 @@ namespace QuestPDF.Elements { ChildrenQueue = new Queue(Children); - container.Stack(stack => + container.Column(column => { - stack.Spacing(VerticalSpacing); + column.Spacing(VerticalSpacing); while (ChildrenQueue.Any()) - stack.Item().Row(BuildRow); + column.Item().Row(BuildRow); }); } @@ -65,12 +65,12 @@ namespace QuestPDF.Elements emptySpace /= 2; if (hasEmptySpace && Alignment != HorizontalAlignment.Left) - row.RelativeColumn(emptySpace); + row.RelativeItem(emptySpace); - elements.ForEach(x => row.RelativeColumn(x.Columns).Element(x.Child)); + elements.ForEach(x => row.RelativeItem(x.Columns).Element(x.Child)); if (hasEmptySpace && Alignment != HorizontalAlignment.Right) - row.RelativeColumn(emptySpace); + row.RelativeItem(emptySpace); } } } \ No newline at end of file diff --git a/QuestPDF/Elements/Line.cs b/QuestPDF/Elements/Line.cs new file mode 100644 index 0000000..0d21d38 --- /dev/null +++ b/QuestPDF/Elements/Line.cs @@ -0,0 +1,45 @@ +using QuestPDF.Drawing; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Elements +{ + public interface ILine + { + + } + + internal enum LineType + { + Vertical, + Horizontal + } + + internal class Line : Element, ILine, ICacheable + { + public LineType Type { get; set; } + public string Color { get; set; } + public float Size { get; set; } + + internal override SpacePlan Measure(Size availableSpace) + { + return Type switch + { + LineType.Vertical when availableSpace.Width >= Size => SpacePlan.FullRender(Size, 0), + LineType.Horizontal when availableSpace.Height >= Size => SpacePlan.FullRender(0, Size), + _ => SpacePlan.Wrap() + }; + } + + internal override void Draw(Size availableSpace) + { + if (Type == LineType.Vertical) + { + Canvas.DrawRectangle(new Position(-Size/2, 0), new Size(Size, availableSpace.Height), Color); + } + else if (Type == LineType.Horizontal) + { + Canvas.DrawRectangle(new Position(0, -Size/2), new Size(availableSpace.Width, Size), Color); + } + } + } +} \ No newline at end of file diff --git a/QuestPDF/Elements/PreventPaging.cs b/QuestPDF/Elements/PreventPaging.cs deleted file mode 100644 index e4c0327..0000000 --- a/QuestPDF/Elements/PreventPaging.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using QuestPDF.Drawing; -using QuestPDF.Infrastructure; - -namespace QuestPDF.Elements -{ - internal class PreventPaging : ContainerElement - { - internal override SpacePlan Measure(Size availableSpace) - { - if (Child == null) - return SpacePlan.FullRender(Size.Zero); - - var measurement = Child.Measure(availableSpace); - - return measurement.Type switch - { - SpacePlanType.Wrap => SpacePlan.FullRender(Size.Zero), - SpacePlanType.PartialRender => SpacePlan.FullRender(measurement), - SpacePlanType.FullRender => measurement, - _ => throw new ArgumentOutOfRangeException() - }; - } - } -} \ No newline at end of file diff --git a/QuestPDF/Elements/Row.cs b/QuestPDF/Elements/Row.cs index 045bd49..ffc157d 100644 --- a/QuestPDF/Elements/Row.cs +++ b/QuestPDF/Elements/Row.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using QuestPDF.Drawing; @@ -6,171 +7,152 @@ using QuestPDF.Infrastructure; namespace QuestPDF.Elements { - internal class RowElement : Constrained + internal enum RowItemType { - public float ConstantSize { get; } - public float RelativeSize { get; } - - public RowElement(float constantSize, float relativeSize) - { - ConstantSize = constantSize; - RelativeSize = relativeSize; - } - - public void SetWidth(float width) - { - MinWidth = width; - MaxWidth = width; - } + Auto, + Constant, + Relative } - internal class BinaryRow : Element, ICacheable, IStateResettable + internal class RowItem : Container { - internal Element Left { get; set; } - internal Element Right { get; set; } - - private bool IsLeftRendered { get; set; } - private bool IsRightRendered { get; set; } + public bool IsRendered { get; set; } + public float Width { get; set; } + public RowItemType Type { get; set; } + public float Size { get; set; } + } + + internal class RowItemRenderingCommand + { + public RowItem RowItem { get; set; } + public SpacePlan Measurement { get; set; } + public Size Size { get; set; } + public Position Offset { get; set; } + } + + internal class Row : Element, ICacheable, IStateResettable + { + internal List Items { get; } = new(); + internal float Spacing { get; set; } + public void ResetState() { - IsLeftRendered = false; - IsRightRendered = false; + Items.ForEach(x => x.IsRendered = false); } internal override IEnumerable GetChildren() { - yield return Left; - yield return Right; + return Items; } internal override void CreateProxy(Func create) { - Left = create(Left); - Right = create(Right); + Items.ForEach(x => x.Child = create(x.Child)); } internal override SpacePlan Measure(Size availableSpace) { - var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height)); - - if (leftMeasurement.Type == SpacePlanType.Wrap) + UpdateItemsWidth(availableSpace.Width); + var renderingCommands = PlanLayout(availableSpace); + + if (renderingCommands.Any(x => !x.RowItem.IsRendered && x.Measurement.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)); + var width = renderingCommands.Last().Offset.X + renderingCommands.Last().Size.Width; + var height = renderingCommands.Max(x => x.Size.Height); + var size = new Size(width, height); - if (rightMeasurement.Type == SpacePlanType.Wrap) + if (width > availableSpace.Width + Size.Epsilon || height > availableSpace.Height + Size.Epsilon) return SpacePlan.Wrap(); - if (leftMeasurement.Type == SpacePlanType.FullRender) - IsRightRendered = true; - - var totalWidth = leftMeasurement.Width + rightMeasurement.Width; - var totalHeight = Math.Max(leftMeasurement.Height, rightMeasurement.Height); + if (renderingCommands.Any(x => !x.RowItem.IsRendered && x.Measurement.Type == SpacePlanType.PartialRender)) + return SpacePlan.PartialRender(size); - var targetSize = new Size(totalWidth, totalHeight); - - if ((!IsLeftRendered && leftMeasurement.Type == SpacePlanType.PartialRender) || - (!IsRightRendered && rightMeasurement.Type == SpacePlanType.PartialRender)) - return SpacePlan.PartialRender(targetSize); - - return SpacePlan.FullRender(targetSize); + return SpacePlan.FullRender(size); } internal override void Draw(Size availableSpace) { - var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height)); - var leftWidth = leftMeasurement.Width; - - Left.Draw(new Size(leftWidth, availableSpace.Height)); - - Canvas.Translate(new Position(leftWidth, 0)); - Right.Draw(new Size(availableSpace.Width - leftWidth, availableSpace.Height)); - Canvas.Translate(new Position(-leftWidth, 0)); - } - } - - internal class Row : Element - { - public float Spacing { get; set; } = 0; - - public ICollection Items { get; internal set; } = new List(); - private Element? RootElement { get; set; } + UpdateItemsWidth(availableSpace.Width); + var renderingCommands = PlanLayout(availableSpace); - internal override IEnumerable GetChildren() - { - if (RootElement == null) - ComposeTree(); - - yield return RootElement; - } - - internal override SpacePlan Measure(Size availableSpace) - { - UpdateElementsWidth(availableSpace.Width); - return RootElement.Measure(availableSpace); - } - - internal override void Draw(Size availableSpace) - { - UpdateElementsWidth(availableSpace.Width); - RootElement.Draw(availableSpace); - } - - #region structure - - private void ComposeTree() - { - Items = AddSpacing(Items, Spacing); - - var elements = Items.Cast().ToArray(); - RootElement = BuildTree(elements); - } - - private void UpdateElementsWidth(float availableWidth) - { - var constantWidth = Items.Sum(x => x.ConstantSize); - var relativeWidth = Items.Sum(x => x.RelativeSize); - - var widthPerRelativeUnit = (relativeWidth > 0) ? (availableWidth - constantWidth) / relativeWidth : 0; - - foreach (var row in Items) + foreach (var command in renderingCommands) { - row.SetWidth(row.ConstantSize + row.RelativeSize * widthPerRelativeUnit); + if (command.Measurement.Type == SpacePlanType.FullRender) + command.RowItem.IsRendered = true; + + if (command.Measurement.Type == SpacePlanType.Wrap) + continue; + + Canvas.Translate(command.Offset); + command.RowItem.Draw(command.Size); + Canvas.Translate(command.Offset.Reverse()); + } + + if (Items.All(x => x.IsRendered)) + ResetState(); + } + + private void UpdateItemsWidth(float availableWidth) + { + HandleItemsWithAutoWidth(); + + var constantWidth = Items.Where(x => x.Type == RowItemType.Constant).Sum(x => x.Size); + var relativeWidth = Items.Where(x => x.Type == RowItemType.Relative).Sum(x => x.Size); + var spacingWidth = (Items.Count - 1) * Spacing; + + foreach (var item in Items.Where(x => x.Type == RowItemType.Constant)) + item.Width = item.Size; + + if (relativeWidth <= 0) + return; + + var widthPerRelativeUnit = (availableWidth - constantWidth - spacingWidth) / relativeWidth; + + foreach (var item in Items.Where(x => x.Type == RowItemType.Relative)) + item.Width = item.Size * widthPerRelativeUnit; + } + + private void HandleItemsWithAutoWidth() + { + foreach (var rowItem in Items.Where(x => x.Type == RowItemType.Auto)) + { + rowItem.Size = rowItem.Measure(Size.Max).Width; + rowItem.Type = RowItemType.Constant; } } - - private static ICollection AddSpacing(ICollection elements, float spacing) + + private ICollection PlanLayout(Size availableSpace) { - if (spacing < Size.Epsilon) - return elements; - - return elements - .SelectMany(x => new[] { new RowElement(spacing, 0), x }) - .Skip(1) - .ToList(); - } + var leftOffset = 0f; + var renderingCommands = new List(); - private static Element BuildTree(Span elements) - { - if (elements.IsEmpty) - return Empty.Instance; - - if (elements.Length == 1) - return elements[0]; - - var half = elements.Length / 2; - - return new BinaryRow + foreach (var item in Items) { - Left = BuildTree(elements.Slice(0, half)), - Right = BuildTree(elements.Slice(half)) - }; + var itemSpace = new Size(item.Width, availableSpace.Height); + + var command = new RowItemRenderingCommand + { + RowItem = item, + Size = itemSpace, + Measurement = item.Measure(itemSpace), + Offset = new Position(leftOffset, 0) + }; + + renderingCommands.Add(command); + leftOffset += item.Width + Spacing; + } + + var rowHeight = renderingCommands.Where(x => !x.RowItem.IsRendered).Max(x => x.Measurement.Height); + + renderingCommands.ForEach(command => + { + command.Size = new Size(command.Size.Width, rowHeight); + command.Measurement = command.RowItem.Measure(command.Size); + }); + + return renderingCommands; } - - #endregion } } \ No newline at end of file diff --git a/QuestPDF/Elements/RowOld.cs b/QuestPDF/Elements/RowOld.cs new file mode 100644 index 0000000..7f2776c --- /dev/null +++ b/QuestPDF/Elements/RowOld.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using QuestPDF.Drawing; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Elements +{ + // TODO: remove + internal class RowOldElement : Constrained + { + public float ConstantSize { get; } + public float RelativeSize { get; } + + public RowOldElement(float constantSize, float relativeSize) + { + ConstantSize = constantSize; + RelativeSize = relativeSize; + } + + public void SetWidth(float width) + { + MinWidth = width; + MaxWidth = width; + } + } + + // TODO: remove + internal class BinaryRow : Element, ICacheable, IStateResettable + { + internal Element Left { get; set; } + internal Element Right { get; set; } + + private bool IsLeftRendered { get; set; } + private bool IsRightRendered { get; set; } + + public void ResetState() + { + IsLeftRendered = false; + IsRightRendered = false; + } + + internal override IEnumerable GetChildren() + { + yield return Left; + yield return Right; + } + + internal override void CreateProxy(Func create) + { + Left = create(Left); + Right = create(Right); + } + + internal override SpacePlan Measure(Size availableSpace) + { + var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height)); + + 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); + + var targetSize = new Size(totalWidth, totalHeight); + + if ((!IsLeftRendered && leftMeasurement.Type == SpacePlanType.PartialRender) || + (!IsRightRendered && rightMeasurement.Type == SpacePlanType.PartialRender)) + return SpacePlan.PartialRender(targetSize); + + return SpacePlan.FullRender(targetSize); + } + + internal override void Draw(Size availableSpace) + { + var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height)); + var leftWidth = leftMeasurement.Width; + + Left.Draw(new Size(leftWidth, availableSpace.Height)); + + Canvas.Translate(new Position(leftWidth, 0)); + Right.Draw(new Size(availableSpace.Width - leftWidth, availableSpace.Height)); + Canvas.Translate(new Position(-leftWidth, 0)); + } + } + + // TODO: remove + internal class RowOld : Element + { + public float Spacing { get; set; } = 0; + + public ICollection Items { get; internal set; } = new List(); + private Element? RootElement { get; set; } + + internal override IEnumerable GetChildren() + { + if (RootElement == null) + ComposeTree(); + + yield return RootElement; + } + + internal override SpacePlan Measure(Size availableSpace) + { + UpdateElementsWidth(availableSpace.Width); + return RootElement.Measure(availableSpace); + } + + internal override void Draw(Size availableSpace) + { + UpdateElementsWidth(availableSpace.Width); + RootElement.Draw(availableSpace); + } + + #region structure + + private void ComposeTree() + { + Items = AddSpacing(Items, Spacing); + + var elements = Items.Cast().ToArray(); + RootElement = BuildTree(elements); + } + + private void UpdateElementsWidth(float availableWidth) + { + var constantWidth = Items.Sum(x => x.ConstantSize); + var relativeWidth = Items.Sum(x => x.RelativeSize); + + var widthPerRelativeUnit = (relativeWidth > 0) ? (availableWidth - constantWidth) / relativeWidth : 0; + + foreach (var row in Items) + { + row.SetWidth(row.ConstantSize + row.RelativeSize * widthPerRelativeUnit); + } + } + + private static ICollection AddSpacing(ICollection elements, float spacing) + { + if (spacing < Size.Epsilon) + return elements; + + return elements + .SelectMany(x => new[] { new RowOldElement(spacing, 0), x }) + .Skip(1) + .ToList(); + } + + private static Element BuildTree(Span elements) + { + if (elements.IsEmpty) + return Empty.Instance; + + if (elements.Length == 1) + return elements[0]; + + var half = elements.Length / 2; + + return new BinaryRow + { + Left = BuildTree(elements.Slice(0, half)), + Right = BuildTree(elements.Slice(half)) + }; + } + + #endregion + } +} \ No newline at end of file diff --git a/QuestPDF/Elements/Stack.cs b/QuestPDF/Elements/Stack.cs index b190498..e72864f 100644 --- a/QuestPDF/Elements/Stack.cs +++ b/QuestPDF/Elements/Stack.cs @@ -9,7 +9,8 @@ using IContainer = QuestPDF.Infrastructure.IContainer; namespace QuestPDF.Elements { - internal class BinaryStack : Element, IStateResettable, ICacheable + // TODO: remove + internal class Binarycolumn : Element, IStateResettable, ICacheable { internal Element First { get; set; } = Empty.Instance; internal Element Second { get; set; } = Empty.Instance; @@ -93,7 +94,8 @@ namespace QuestPDF.Elements } } - internal class Stack : IComponent + // TODO: remove + internal class column : IComponent { public ICollection Items { get; } = new List(); public float Spacing { get; set; } = 0; @@ -133,7 +135,7 @@ namespace QuestPDF.Elements var half = elements.Length / 2; - return new BinaryStack + return new Binarycolumn { First = BuildTree(elements.Slice(0, half)), Second = BuildTree(elements.Slice(half)) diff --git a/QuestPDF/Fluent/ColumnExtensions.cs b/QuestPDF/Fluent/ColumnExtensions.cs new file mode 100644 index 0000000..8d931d0 --- /dev/null +++ b/QuestPDF/Fluent/ColumnExtensions.cs @@ -0,0 +1,47 @@ +using System; +using QuestPDF.Elements; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Fluent +{ + public class ColumnDescriptor + { + //internal column Column { get; } = new(); + internal Column Column { get; } = new(); + + public void Spacing(float value) + { + Column.Spacing = value; + } + + public IContainer Item() + { + var container = new Container(); + + Column.Items.Add(new ColumnItem() + { + Child = container + }); + + return container; + } + } + + public static class ColumnExtensions + { + // TODO: deprecated Box method in QuestPDF 2022.2 + [Obsolete("This element has been renamed. Please use the Column method.")] + public static void Stack(this IContainer element, Action handler) + { + element.Column(handler); + } + + public static void Column(this IContainer element, Action handler) + { + var descriptor = new ColumnDescriptor(); + handler(descriptor); + element.Element(descriptor.Column); + //element.Component(descriptor.Column); + } + } +} \ No newline at end of file diff --git a/QuestPDF/Fluent/DecorationExtensions.cs b/QuestPDF/Fluent/DecorationExtensions.cs index d8cc7d6..3b6cf67 100644 --- a/QuestPDF/Fluent/DecorationExtensions.cs +++ b/QuestPDF/Fluent/DecorationExtensions.cs @@ -52,7 +52,7 @@ namespace QuestPDF.Fluent var descriptor = new DecorationDescriptor(); handler(descriptor); - element.Component(descriptor.Decoration); + element.Element(descriptor.Decoration); } } } \ No newline at end of file diff --git a/QuestPDF/Fluent/ElementExtensions.cs b/QuestPDF/Fluent/ElementExtensions.cs index 54fc738..8ac8271 100644 --- a/QuestPDF/Fluent/ElementExtensions.cs +++ b/QuestPDF/Fluent/ElementExtensions.cs @@ -160,12 +160,7 @@ namespace QuestPDF.Fluent TextStyle = textStyle }); } - - public static IContainer PreventPaging(this IContainer element) - { - return element.Element(new PreventPaging()); - } - + public static IContainer ScaleToFit(this IContainer element) { return element.Element(new ScaleToFit()); diff --git a/QuestPDF/Fluent/LineExtensions.cs b/QuestPDF/Fluent/LineExtensions.cs new file mode 100644 index 0000000..8e05315 --- /dev/null +++ b/QuestPDF/Fluent/LineExtensions.cs @@ -0,0 +1,36 @@ +using System; +using QuestPDF.Elements; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Fluent +{ + public static class LineExtensions + { + private static ILine Line(this IContainer element, LineType type, float size) + { + var line = new Line + { + Size = size, + Type = type + }; + + element.Element(line); + return line; + } + + public static ILine LineVertical(this IContainer element, float size) + { + return element.Line(LineType.Vertical, size); + } + + public static ILine LineHorizontal(this IContainer element, float size) + { + return element.Line(LineType.Horizontal, size); + } + + public static void LineColor(this ILine descriptor, string value) + { + (descriptor as Line).Color = value; + } + } +} \ No newline at end of file diff --git a/QuestPDF/Fluent/RowExtensions.cs b/QuestPDF/Fluent/RowExtensions.cs index 25bba30..1db8c0a 100644 --- a/QuestPDF/Fluent/RowExtensions.cs +++ b/QuestPDF/Fluent/RowExtensions.cs @@ -6,30 +6,53 @@ namespace QuestPDF.Fluent { public class RowDescriptor { - internal Row Row { get; } = new Row(); + internal Row Row { get; } = new(); public void Spacing(float value) { Row.Spacing = value; } - - public IContainer ConstantColumn(float width) + + private IContainer Item(RowItemType type, float size = 0) { - return Column(constantWidth: width); - } - - public IContainer RelativeColumn(float width = 1) - { - return Column(relativeWidth: width); - } - - public IContainer Column(float constantWidth = 0, float relativeWidth = 0) - { - var element = new RowElement(constantWidth, relativeWidth); + var element = new RowItem + { + Type = type, + Size = size + }; Row.Items.Add(element); return element; } + + // TODO: deprecated Box method in QuestPDF 2022.2 + [Obsolete("This element has been renamed. Please use the RelativeItem method.")] + public IContainer RelativeColumn(float size = 1) + { + return Item(RowItemType.Relative, size); + } + + // TODO: deprecated Box method in QuestPDF 2022.2 + [Obsolete("This element has been renamed. Please use the ConstantItem method.")] + public IContainer ConstantColumn(float size) + { + return Item(RowItemType.Constant, size); + } + + public IContainer RelativeItem(float size = 1) + { + return Item(RowItemType.Relative, size); + } + + public IContainer ConstantItem(float size) + { + return Item(RowItemType.Constant, size); + } + + public IContainer AutoItem() + { + return Item(RowItemType.Auto); + } } public static class RowExtensions diff --git a/QuestPDF/Fluent/RowOldExtensions.cs b/QuestPDF/Fluent/RowOldExtensions.cs new file mode 100644 index 0000000..9104c6f --- /dev/null +++ b/QuestPDF/Fluent/RowOldExtensions.cs @@ -0,0 +1,44 @@ +// using System; +// using QuestPDF.Elements; +// using QuestPDF.Infrastructure; +// +// namespace QuestPDF.Fluent +// { +// public class RowDescriptor +// { +// internal RowOld Row { get; } = new RowOld(); +// +// public void Spacing(float value) +// { +// Row.Spacing = value; +// } +// +// public IContainer ConstantItem(float width) +// { +// return Column(constantWidth: width); +// } +// +// public IContainer RelativeItem(float width = 1) +// { +// return Column(relativeWidth: width); +// } +// +// public IContainer Column(float constantWidth = 0, float relativeWidth = 0) +// { +// var element = new RowOldElement(constantWidth, relativeWidth); +// +// Row.Items.Add(element); +// return element; +// } +// } +// +// public static class RowExtensions +// { +// public static void Row(this IContainer element, Action handler) +// { +// var descriptor = new RowDescriptor(); +// handler(descriptor); +// element.Element(descriptor.Row); +// } +// } +// } \ No newline at end of file diff --git a/QuestPDF/Fluent/StackExtensions.cs b/QuestPDF/Fluent/StackExtensions.cs deleted file mode 100644 index dd14048..0000000 --- a/QuestPDF/Fluent/StackExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using QuestPDF.Elements; -using QuestPDF.Infrastructure; - -namespace QuestPDF.Fluent -{ - public class StackDescriptor - { - internal Stack Stack { get; } = new Stack(); - - public void Spacing(float value) - { - Stack.Spacing = value; - } - - public IContainer Item() - { - var container = new Container(); - Stack.Items.Add(container); - return container; - } - } - - public static class StackExtensions - { - public static void Stack(this IContainer element, Action handler) - { - var descriptor = new StackDescriptor(); - handler(descriptor); - element.Component(descriptor.Stack); - } - } -} \ No newline at end of file diff --git a/QuestPDF/Fluent/TextExtensions.cs b/QuestPDF/Fluent/TextExtensions.cs index c08cfd6..b4359e5 100644 --- a/QuestPDF/Fluent/TextExtensions.cs +++ b/QuestPDF/Fluent/TextExtensions.cs @@ -174,12 +174,12 @@ namespace QuestPDF.Fluent { TextBlocks.ToList().ForEach(x => x.Alignment = Alignment); - container.DefaultTextStyle(DefaultStyle).Stack(stack => + container.DefaultTextStyle(DefaultStyle).Column(column => { - stack.Spacing(Spacing); + column.Spacing(Spacing); foreach (var textBlock in TextBlocks) - stack.Item().Element(textBlock); + column.Item().Element(textBlock); }); } } diff --git a/QuestPDF/Resources/Description.md b/QuestPDF/Resources/Description.md index d3f8432..b1a444d 100644 --- a/QuestPDF/Resources/Description.md +++ b/QuestPDF/Resources/Description.md @@ -71,15 +71,15 @@ void ComposeHeader(IContainer container) container.Row(row => { { - stack.Item().Text($"Invoice #{Model.InvoiceNumber}", titleStyle); + column.Item().Text($"Invoice #{Model.InvoiceNumber}", titleStyle); - stack.Item().Text(text => + column.Item().Text(text => { text.Span("Issue date: ", TextStyle.Default.SemiBold()); text.Span($"{Model.IssueDate:d}"); }); - stack.Item().Text(text => + column.Item().Text(text => { text.Span("Due date: ", TextStyle.Default.SemiBold()); text.Span($"{Model.DueDate:d}"); @@ -97,7 +97,7 @@ Implementation of **the content area** that contains seller and customer details ```csharp void ComposeContent(IContainer container) { - container.PaddingVertical(40).Stack(column => + container.PaddingVertical(40).column(column => { column.Spacing(20); @@ -147,7 +147,7 @@ void ComposeTable(IContainer container) // content decoration .Content() - .Stack(column => + .column(column => { foreach (var item in Model.Items) { @@ -174,7 +174,7 @@ void ComposeTable(IContainer container) ```csharp void ComposeComments(IContainer container) { - container.ShowEntire().Background(Colors.Grey.Lighten3).Padding(10).Stack(message => + container.ShowEntire().Background(Colors.Grey.Lighten3).Padding(10).column(message => { message.Spacing(5); message.Item().Text("Comments", TextStyle.Default.Size(14).SemiBold()); @@ -200,7 +200,7 @@ public class AddressComponent : IComponent public void Compose(IContainer container) { - container.ShowEntire().Stack(column => + container.ShowEntire().column(column => { column.Spacing(5); From b2cc7bbd36504e3d6bad166b10865d21e85a9c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Sun, 16 Jan 2022 17:08:57 +0100 Subject: [PATCH 06/17] Renamed Decoration element --- QuestPDF.Examples/ElementExamples.cs | 4 +- QuestPDF.Examples/InlinedExamples.cs | 2 +- QuestPDF.Examples/TextBenchmark.cs | 2 +- .../Layouts/SectionTemplate.cs | 2 +- .../Layouts/TableOfContentsTemplate.cs | 2 +- QuestPDF/Elements/Decoration.cs | 34 +++++++------- QuestPDF/Elements/Page.cs | 4 +- QuestPDF/Fluent/DecorationExtensions.cs | 44 +++++++++++++++---- QuestPDF/Fluent/TableExtensions.cs | 4 +- 9 files changed, 63 insertions(+), 35 deletions(-) diff --git a/QuestPDF.Examples/ElementExamples.cs b/QuestPDF.Examples/ElementExamples.cs index cdcbd3b..635961c 100644 --- a/QuestPDF.Examples/ElementExamples.cs +++ b/QuestPDF.Examples/ElementExamples.cs @@ -40,7 +40,7 @@ namespace QuestPDF.Examples .Decoration(decoration => { decoration - .Header() + .Before() .Background(Colors.Grey.Medium) .Padding(10) .Text("Notes", TextStyle.Default.Size(16).Color("#FFF")); @@ -501,7 +501,7 @@ namespace QuestPDF.Examples .SemiBold(); decoration - .Header() + .Before() .PaddingBottom(10) .Text("Example: scale component", headerFontStyle); diff --git a/QuestPDF.Examples/InlinedExamples.cs b/QuestPDF.Examples/InlinedExamples.cs index 72c7e1e..fce4c85 100644 --- a/QuestPDF.Examples/InlinedExamples.cs +++ b/QuestPDF.Examples/InlinedExamples.cs @@ -25,7 +25,7 @@ namespace QuestPDF.Examples .Padding(25) .Decoration(decoration => { - decoration.Header().Text(text => + decoration.Before().Text(text => { text.DefaultTextStyle(TextStyle.Default.Size(20)); diff --git a/QuestPDF.Examples/TextBenchmark.cs b/QuestPDF.Examples/TextBenchmark.cs index 4adaee9..47645a3 100644 --- a/QuestPDF.Examples/TextBenchmark.cs +++ b/QuestPDF.Examples/TextBenchmark.cs @@ -129,7 +129,7 @@ namespace QuestPDF.Examples column.Item().Element(Acknowledgements); }); - decoration.Footer().Element(Footer); + decoration.After().Element(Footer); }); } diff --git a/QuestPDF.ReportSample/Layouts/SectionTemplate.cs b/QuestPDF.ReportSample/Layouts/SectionTemplate.cs index 361277a..2e37ec3 100644 --- a/QuestPDF.ReportSample/Layouts/SectionTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/SectionTemplate.cs @@ -21,7 +21,7 @@ namespace QuestPDF.ReportSample.Layouts .Decoration(decoration => { decoration - .Header() + .Before() .PaddingBottom(5) .Text(Model.Title, Typography.Headline); diff --git a/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs b/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs index a3cb715..3f93f93 100644 --- a/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs +++ b/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs @@ -19,7 +19,7 @@ namespace QuestPDF.ReportSample.Layouts .Decoration(decoration => { decoration - .Header() + .Before() .PaddingBottom(5) .Text("Table of contents", Typography.Headline); diff --git a/QuestPDF/Elements/Decoration.cs b/QuestPDF/Elements/Decoration.cs index 7b2fcd7..12e9646 100644 --- a/QuestPDF/Elements/Decoration.cs +++ b/QuestPDF/Elements/Decoration.cs @@ -17,22 +17,22 @@ namespace QuestPDF.Elements internal class Decoration : Element, ICacheable { - internal Element Header { get; set; } = new Empty(); + internal Element Before { get; set; } = new Empty(); internal Element Content { get; set; } = new Empty(); - internal Element Footer { get; set; } = new Empty(); + internal Element After { get; set; } = new Empty(); internal override IEnumerable GetChildren() { - yield return Header; + yield return Before; yield return Content; - yield return Footer; + yield return After; } internal override void CreateProxy(Func create) { - Header = create(Header); + Before = create(Before); Content = create(Content); - Footer = create(Footer); + After = create(After); } internal override SpacePlan Measure(Size availableSpace) @@ -68,17 +68,17 @@ namespace QuestPDF.Elements private IEnumerable PlanLayout(Size availableSpace) { - var headerMeasurement = Header.Measure(availableSpace); - var footerMeasurement = Footer.Measure(availableSpace); + var beforeMeasurement = Before.Measure(availableSpace); + var afterMeasurement = After.Measure(availableSpace); - var contentSpace = new Size(availableSpace.Width, availableSpace.Height - headerMeasurement.Height - footerMeasurement.Height); + var contentSpace = new Size(availableSpace.Width, availableSpace.Height - beforeMeasurement.Height - afterMeasurement.Height); var contentMeasurement = Content.Measure(contentSpace); yield return new DecorationItemRenderingCommand { - Element = Header, - Measurement = headerMeasurement, - Size = new Size(availableSpace.Width, headerMeasurement.Height), + Element = Before, + Measurement = beforeMeasurement, + Size = new Size(availableSpace.Width, beforeMeasurement.Height), Offset = Position.Zero }; @@ -87,15 +87,15 @@ namespace QuestPDF.Elements Element = Content, Measurement = contentMeasurement, Size = new Size(availableSpace.Width, contentMeasurement.Height), - Offset = new Position(0, headerMeasurement.Height) + Offset = new Position(0, beforeMeasurement.Height) }; yield return new DecorationItemRenderingCommand { - Element = Footer, - Measurement = footerMeasurement, - Size = new Size(availableSpace.Width, footerMeasurement.Height), - Offset = new Position(0, headerMeasurement.Height + contentMeasurement.Height) + Element = After, + Measurement = afterMeasurement, + Size = new Size(availableSpace.Width, afterMeasurement.Height), + Offset = new Position(0, beforeMeasurement.Height + contentMeasurement.Height) }; } } diff --git a/QuestPDF/Elements/Page.cs b/QuestPDF/Elements/Page.cs index 0368409..7d06bbe 100644 --- a/QuestPDF/Elements/Page.cs +++ b/QuestPDF/Elements/Page.cs @@ -45,7 +45,7 @@ namespace QuestPDF.Elements .Decoration(decoration => { decoration - .Header() + .Before() .DebugPointer("Page header") .Element(Header); @@ -57,7 +57,7 @@ namespace QuestPDF.Elements .Element(Content); decoration - .Footer() + .After() .DebugPointer("Page footer") .Element(Footer); }); diff --git a/QuestPDF/Fluent/DecorationExtensions.cs b/QuestPDF/Fluent/DecorationExtensions.cs index 3b6cf67..4dfec71 100644 --- a/QuestPDF/Fluent/DecorationExtensions.cs +++ b/QuestPDF/Fluent/DecorationExtensions.cs @@ -8,16 +8,16 @@ namespace QuestPDF.Fluent { internal Decoration Decoration { get; } = new Decoration(); - public IContainer Header() + public IContainer Before() { var container = new Container(); - Decoration.Header = container; + Decoration.Before = container; return container; } - public void Header(Action handler) + public void Before(Action handler) { - handler?.Invoke(Header()); + handler?.Invoke(Before()); } public IContainer Content() @@ -32,17 +32,45 @@ namespace QuestPDF.Fluent handler?.Invoke(Content()); } - public IContainer Footer() + public IContainer After() { var container = new Container(); - Decoration.Footer = container; + Decoration.After = container; return container; } - public void Footer(Action handler) + public void After(Action handler) { - handler?.Invoke(Footer()); + handler?.Invoke(After()); } + + #region Obsolete + + // public IContainer Header() + // { + // var container = new Container(); + // Decoration.Before = container; + // return container; + // } + // + // public void Header(Action handler) + // { + // handler?.Invoke(Header()); + // } + // + // public IContainer Footer() + // { + // var container = new Container(); + // Decoration.After = container; + // return container; + // } + // + // public void Footer(Action handler) + // { + // handler?.Invoke(Footer()); + // } + + #endregion } public static class DecorationExtensions diff --git a/QuestPDF/Fluent/TableExtensions.cs b/QuestPDF/Fluent/TableExtensions.cs index 8e66257..e0af338 100644 --- a/QuestPDF/Fluent/TableExtensions.cs +++ b/QuestPDF/Fluent/TableExtensions.cs @@ -101,9 +101,9 @@ namespace QuestPDF.Fluent container .Decoration(decoration => { - decoration.Header().Element(HeaderTable); + decoration.Before().Element(HeaderTable); decoration.Content().Element(ContentTable); - decoration.Footer().Element(FooterTable); + decoration.After().Element(FooterTable); }); return container; From 272b0fc11a74633cefb67ac1aaeaa1576ec23a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Tue, 18 Jan 2022 23:14:57 +0100 Subject: [PATCH 07/17] Added support for unit types --- QuestPDF.Examples/ColumnExamples.cs | 5 +- QuestPDF.Examples/DebuggingTesting.cs | 2 +- .../DifferentHeaderOnFirstPageExample.cs | 2 +- QuestPDF/Fluent/BorderExtensions.cs | 34 +++++++----- QuestPDF/Fluent/ColumnExtensions.cs | 8 ++- QuestPDF/Fluent/ConstrainedExtensions.cs | 28 +++++----- QuestPDF/Fluent/DecorationExtensions.cs | 54 +++++++++++-------- QuestPDF/Fluent/GridExtensions.cs | 14 ++--- QuestPDF/Fluent/InlinedExtensions.cs | 17 ++++-- QuestPDF/Fluent/LineExtensions.cs | 8 +-- QuestPDF/Fluent/PaddingExtensions.cs | 34 +++++++----- QuestPDF/Fluent/PageExtensions.cs | 48 ++++++++++------- QuestPDF/Fluent/RowExtensions.cs | 4 +- QuestPDF/Fluent/RowOldExtensions.cs | 44 --------------- QuestPDF/Fluent/TableExtensions.cs | 6 +-- QuestPDF/Fluent/TextExtensions.cs | 4 +- QuestPDF/Fluent/TranslateExtensions.cs | 8 +-- QuestPDF/Helpers/PageSizes.cs | 6 +-- QuestPDF/Infrastructure/Unit.cs | 44 +++++++++++++++ 19 files changed, 204 insertions(+), 166 deletions(-) delete mode 100644 QuestPDF/Fluent/RowOldExtensions.cs create mode 100644 QuestPDF/Infrastructure/Unit.cs diff --git a/QuestPDF.Examples/ColumnExamples.cs b/QuestPDF.Examples/ColumnExamples.cs index 40d60b4..3c5a222 100644 --- a/QuestPDF.Examples/ColumnExamples.cs +++ b/QuestPDF.Examples/ColumnExamples.cs @@ -25,8 +25,9 @@ namespace QuestPDF.Examples static void Block(IContainer container) { container - .Width(100) - .Height(100) + .Width(72) + .Height(3.5f) + .Height(1.5f) .Background(Placeholders.BackgroundColor()); } }); diff --git a/QuestPDF.Examples/DebuggingTesting.cs b/QuestPDF.Examples/DebuggingTesting.cs index 7aa2deb..c8434da 100644 --- a/QuestPDF.Examples/DebuggingTesting.cs +++ b/QuestPDF.Examples/DebuggingTesting.cs @@ -9,7 +9,7 @@ namespace QuestPDF.Examples public class DebuggingTesting { [Test] - public void column() + public void Column() { Assert.Throws(() => { diff --git a/QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs b/QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs index 0f0c354..4c2b733 100644 --- a/QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs +++ b/QuestPDF.Examples/DifferentHeaderOnFirstPageExample.cs @@ -23,7 +23,7 @@ namespace QuestPDF.Examples container.Page(page => { page.Size(PageSizes.A6); - page.Margin(30); + page.Margin(5); page.Background(Colors.White); page.Header().Column(column => diff --git a/QuestPDF/Fluent/BorderExtensions.cs b/QuestPDF/Fluent/BorderExtensions.cs index deafa13..32e94f1 100644 --- a/QuestPDF/Fluent/BorderExtensions.cs +++ b/QuestPDF/Fluent/BorderExtensions.cs @@ -14,39 +14,45 @@ namespace QuestPDF.Fluent return element.Element(border); } - public static IContainer Border(this IContainer element, float value) + public static IContainer Border(this IContainer element, float value, Unit unit = Unit.Point) { - return element.BorderHorizontal(value).BorderVertical(value); + return element + .BorderHorizontal(value, unit) + .BorderVertical(value, unit); } - public static IContainer BorderVertical(this IContainer element, float value) + public static IContainer BorderVertical(this IContainer element, float value, Unit unit = Unit.Point) { - return element.BorderLeft(value).BorderRight(value); + return element + .BorderLeft(value, unit) + .BorderRight(value, unit); } - public static IContainer BorderHorizontal(this IContainer element, float value) + public static IContainer BorderHorizontal(this IContainer element, float value, Unit unit = Unit.Point) { - return element.BorderTop(value).BorderBottom(value); + return element + .BorderTop(value, unit) + .BorderBottom(value, unit); } - public static IContainer BorderLeft(this IContainer element, float value) + public static IContainer BorderLeft(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Border(x => x.Left = value); + return element.Border(x => x.Left = value.ToPoints(unit)); } - public static IContainer BorderRight(this IContainer element, float value) + public static IContainer BorderRight(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Border(x => x.Right = value); + return element.Border(x => x.Right = value.ToPoints(unit)); } - public static IContainer BorderTop(this IContainer element, float value) + public static IContainer BorderTop(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Border(x => x.Top = value); + return element.Border(x => x.Top = value.ToPoints(unit)); } - public static IContainer BorderBottom(this IContainer element, float value) + public static IContainer BorderBottom(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Border(x => x.Bottom = value); + return element.Border(x => x.Bottom = value.ToPoints(unit)); } public static IContainer BorderColor(this IContainer element, string color) diff --git a/QuestPDF/Fluent/ColumnExtensions.cs b/QuestPDF/Fluent/ColumnExtensions.cs index 8d931d0..a16a299 100644 --- a/QuestPDF/Fluent/ColumnExtensions.cs +++ b/QuestPDF/Fluent/ColumnExtensions.cs @@ -6,19 +6,18 @@ namespace QuestPDF.Fluent { public class ColumnDescriptor { - //internal column Column { get; } = new(); internal Column Column { get; } = new(); - public void Spacing(float value) + public void Spacing(float value, Unit unit = Unit.Point) { - Column.Spacing = value; + Column.Spacing = value.ToPoints(unit); } public IContainer Item() { var container = new Container(); - Column.Items.Add(new ColumnItem() + Column.Items.Add(new ColumnItem { Child = container }); @@ -41,7 +40,6 @@ namespace QuestPDF.Fluent var descriptor = new ColumnDescriptor(); handler(descriptor); element.Element(descriptor.Column); - //element.Component(descriptor.Column); } } } \ No newline at end of file diff --git a/QuestPDF/Fluent/ConstrainedExtensions.cs b/QuestPDF/Fluent/ConstrainedExtensions.cs index bb30da2..0f64abe 100644 --- a/QuestPDF/Fluent/ConstrainedExtensions.cs +++ b/QuestPDF/Fluent/ConstrainedExtensions.cs @@ -14,34 +14,38 @@ namespace QuestPDF.Fluent return element.Element(constrained); } - public static IContainer Width(this IContainer element, float value) + public static IContainer Width(this IContainer element, float value, Unit unit = Unit.Point) { - return element.MinWidth(value).MaxWidth(value); + return element + .MinWidth(value, unit) + .MaxWidth(value, unit); } - public static IContainer MinWidth(this IContainer element, float value) + public static IContainer MinWidth(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Constrained(x => x.MinWidth = value); + return element.Constrained(x => x.MinWidth = value.ToPoints(unit)); } - public static IContainer MaxWidth(this IContainer element, float value) + public static IContainer MaxWidth(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Constrained(x => x.MaxWidth = value); + return element.Constrained(x => x.MaxWidth = value.ToPoints(unit)); } - public static IContainer Height(this IContainer element, float value) + public static IContainer Height(this IContainer element, float value, Unit unit = Unit.Point) { - return element.MinHeight(value).MaxHeight(value); + return element + .MinHeight(value, unit) + .MaxHeight(value, unit); } - public static IContainer MinHeight(this IContainer element, float value) + public static IContainer MinHeight(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Constrained(x => x.MinHeight = value); + return element.Constrained(x => x.MinHeight = value.ToPoints(unit)); } - public static IContainer MaxHeight(this IContainer element, float value) + public static IContainer MaxHeight(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Constrained(x => x.MaxHeight = value); + return element.Constrained(x => x.MaxHeight = value.ToPoints(unit)); } } } \ No newline at end of file diff --git a/QuestPDF/Fluent/DecorationExtensions.cs b/QuestPDF/Fluent/DecorationExtensions.cs index 4dfec71..6be4fbe 100644 --- a/QuestPDF/Fluent/DecorationExtensions.cs +++ b/QuestPDF/Fluent/DecorationExtensions.cs @@ -46,29 +46,37 @@ namespace QuestPDF.Fluent #region Obsolete - // public IContainer Header() - // { - // var container = new Container(); - // Decoration.Before = container; - // return container; - // } - // - // public void Header(Action handler) - // { - // handler?.Invoke(Header()); - // } - // - // public IContainer Footer() - // { - // var container = new Container(); - // Decoration.After = container; - // return container; - // } - // - // public void Footer(Action handler) - // { - // handler?.Invoke(Footer()); - // } + // TODO: deprecated Box method in QuestPDF 2022.2 + [Obsolete("This element has been renamed. Please use the Before method.")] + public IContainer Header() + { + var container = new Container(); + Decoration.Before = container; + return container; + } + + // TODO: deprecated Box method in QuestPDF 2022.2 + [Obsolete("This element has been renamed. Please use the Before method.")] + public void Header(Action handler) + { + handler?.Invoke(Header()); + } + + // TODO: deprecated Box method in QuestPDF 2022.2 + [Obsolete("This element has been renamed. Please use the After method.")] + public IContainer Footer() + { + var container = new Container(); + Decoration.After = container; + return container; + } + + // TODO: deprecated Box method in QuestPDF 2022.2 + [Obsolete("This element has been renamed. Please use the After method.")] + public void Footer(Action handler) + { + handler?.Invoke(Footer()); + } #endregion } diff --git a/QuestPDF/Fluent/GridExtensions.cs b/QuestPDF/Fluent/GridExtensions.cs index d08942e..e7ae0ca 100644 --- a/QuestPDF/Fluent/GridExtensions.cs +++ b/QuestPDF/Fluent/GridExtensions.cs @@ -8,20 +8,20 @@ namespace QuestPDF.Fluent { internal Grid Grid { get; } = new Grid(); - public void Spacing(float value) + public void Spacing(float value, Unit unit = Unit.Point) { - VerticalSpacing(value); - HorizontalSpacing(value); + VerticalSpacing(value, unit); + HorizontalSpacing(value, unit); } - public void VerticalSpacing(float value) + public void VerticalSpacing(float value, Unit unit = Unit.Point) { - Grid.VerticalSpacing = value; + Grid.VerticalSpacing = value.ToPoints(unit); } - public void HorizontalSpacing(float value) + public void HorizontalSpacing(float value, Unit unit = Unit.Point) { - Grid.HorizontalSpacing = value; + Grid.HorizontalSpacing = value.ToPoints(unit); } public void Columns(int value = Grid.DefaultColumnsCount) diff --git a/QuestPDF/Fluent/InlinedExtensions.cs b/QuestPDF/Fluent/InlinedExtensions.cs index b250c49..140185c 100644 --- a/QuestPDF/Fluent/InlinedExtensions.cs +++ b/QuestPDF/Fluent/InlinedExtensions.cs @@ -10,14 +10,21 @@ namespace QuestPDF.Fluent { internal Inlined Inlined { get; } = new Inlined(); - public void Spacing(float value) + public void Spacing(float value, Unit unit = Unit.Point) { - VerticalSpacing(value); - HorizontalSpacing(value); + VerticalSpacing(value, unit); + HorizontalSpacing(value, unit); } - public void VerticalSpacing(float value) => Inlined.VerticalSpacing = value; - public void HorizontalSpacing(float value) => Inlined.HorizontalSpacing = value; + public void VerticalSpacing(float value, Unit unit = Unit.Point) + { + Inlined.VerticalSpacing = value.ToPoints(unit); + } + + public void HorizontalSpacing(float value, Unit unit = Unit.Point) + { + Inlined.HorizontalSpacing = value.ToPoints(unit); + } public void BaselineTop() => Inlined.BaselineAlignment = VerticalAlignment.Top; public void BaselineMiddle() => Inlined.BaselineAlignment = VerticalAlignment.Middle; diff --git a/QuestPDF/Fluent/LineExtensions.cs b/QuestPDF/Fluent/LineExtensions.cs index 8e05315..2dacdcf 100644 --- a/QuestPDF/Fluent/LineExtensions.cs +++ b/QuestPDF/Fluent/LineExtensions.cs @@ -18,14 +18,14 @@ namespace QuestPDF.Fluent return line; } - public static ILine LineVertical(this IContainer element, float size) + public static ILine LineVertical(this IContainer element, float size, Unit unit = Unit.Point) { - return element.Line(LineType.Vertical, size); + return element.Line(LineType.Vertical, size.ToPoints(unit)); } - public static ILine LineHorizontal(this IContainer element, float size) + public static ILine LineHorizontal(this IContainer element, float size, Unit unit = Unit.Point) { - return element.Line(LineType.Horizontal, size); + return element.Line(LineType.Horizontal, size.ToPoints(unit)); } public static void LineColor(this ILine descriptor, string value) diff --git a/QuestPDF/Fluent/PaddingExtensions.cs b/QuestPDF/Fluent/PaddingExtensions.cs index 4cdc892..33d0b46 100644 --- a/QuestPDF/Fluent/PaddingExtensions.cs +++ b/QuestPDF/Fluent/PaddingExtensions.cs @@ -14,39 +14,45 @@ namespace QuestPDF.Fluent return element.Element(padding); } - public static IContainer Padding(this IContainer element, float value) + public static IContainer Padding(this IContainer element, float value, Unit unit = Unit.Point) { - return element.PaddingVertical(value).PaddingHorizontal(value); + return element + .PaddingVertical(value, unit) + .PaddingHorizontal(value, unit); } - public static IContainer PaddingHorizontal(this IContainer element, float value) + public static IContainer PaddingHorizontal(this IContainer element, float value, Unit unit = Unit.Point) { - return element.PaddingLeft(value).PaddingRight(value); + return element + .PaddingLeft(value, unit) + .PaddingRight(value, unit); } - public static IContainer PaddingVertical(this IContainer element, float value) + public static IContainer PaddingVertical(this IContainer element, float value, Unit unit = Unit.Point) { - return element.PaddingTop(value).PaddingBottom(value); + return element + .PaddingTop(value, unit) + .PaddingBottom(value, unit); } - public static IContainer PaddingTop(this IContainer element, float value) + public static IContainer PaddingTop(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Padding(x => x.Top += value); + return element.Padding(x => x.Top += value.ToPoints(unit)); } - public static IContainer PaddingBottom(this IContainer element, float value) + public static IContainer PaddingBottom(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Padding(x => x.Bottom += value); + return element.Padding(x => x.Bottom += value.ToPoints(unit)); } - public static IContainer PaddingLeft(this IContainer element, float value) + public static IContainer PaddingLeft(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Padding(x => x.Left += value); + return element.Padding(x => x.Left += value.ToPoints(unit)); } - public static IContainer PaddingRight(this IContainer element, float value) + public static IContainer PaddingRight(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Padding(x => x.Right += value); + return element.Padding(x => x.Right += value.ToPoints(unit)); } } } \ No newline at end of file diff --git a/QuestPDF/Fluent/PageExtensions.cs b/QuestPDF/Fluent/PageExtensions.cs index 82d7dc5..ab968ee 100644 --- a/QuestPDF/Fluent/PageExtensions.cs +++ b/QuestPDF/Fluent/PageExtensions.cs @@ -10,16 +10,24 @@ namespace QuestPDF.Fluent { internal Page Page { get; } = new Page(); + public void Size(float width, float height, Unit unit = Unit.Inch) + { + var pageSize = new PageSize(width, height, unit); + + MinSize(pageSize); + MaxSize(pageSize); + } + public void Size(PageSize pageSize) { MinSize(pageSize); MaxSize(pageSize); } - public void ContinuousSize(float width) + public void ContinuousSize(float width, Unit unit = Unit.Point) { - MinSize(new PageSize(width, 0)); - MaxSize(new PageSize(width, Infrastructure.Size.Max.Height)); + MinSize(new PageSize(width.ToPoints(unit), 0)); + MaxSize(new PageSize(width.ToPoints(unit), Infrastructure.Size.Max.Height)); } public void MinSize(PageSize pageSize) @@ -32,42 +40,42 @@ namespace QuestPDF.Fluent Page.MaxSize = pageSize; } - public void MarginLeft(float value) + public void MarginLeft(float value, Unit unit = Unit.Point) { - Page.MarginLeft = value; + Page.MarginLeft = value.ToPoints(unit); } - public void MarginRight(float value) + public void MarginRight(float value, Unit unit = Unit.Point) { - Page.MarginRight = value; + Page.MarginRight = value.ToPoints(unit); } - public void MarginTop(float value) + public void MarginTop(float value, Unit unit = Unit.Point) { - Page.MarginTop = value; + Page.MarginTop = value.ToPoints(unit); } - public void MarginBottom(float value) + public void MarginBottom(float value, Unit unit = Unit.Point) { - Page.MarginBottom = value; + Page.MarginBottom = value.ToPoints(unit); } - public void MarginVertical(float value) + public void MarginVertical(float value, Unit unit = Unit.Point) { - MarginTop(value); - MarginBottom(value); + MarginTop(value, unit); + MarginBottom(value, unit); } - public void MarginHorizontal(float value) + public void MarginHorizontal(float value, Unit unit = Unit.Point) { - MarginLeft(value); - MarginRight(value); + MarginLeft(value, unit); + MarginRight(value, unit); } - public void Margin(float value) + public void Margin(float value, Unit unit = Unit.Point) { - MarginVertical(value); - MarginHorizontal(value); + MarginVertical(value, unit); + MarginHorizontal(value, unit); } public void DefaultTextStyle(TextStyle textStyle) diff --git a/QuestPDF/Fluent/RowExtensions.cs b/QuestPDF/Fluent/RowExtensions.cs index 1db8c0a..2968eef 100644 --- a/QuestPDF/Fluent/RowExtensions.cs +++ b/QuestPDF/Fluent/RowExtensions.cs @@ -44,9 +44,9 @@ namespace QuestPDF.Fluent return Item(RowItemType.Relative, size); } - public IContainer ConstantItem(float size) + public IContainer ConstantItem(float size, Unit unit = Unit.Point) { - return Item(RowItemType.Constant, size); + return Item(RowItemType.Constant, size.ToPoints(unit)); } public IContainer AutoItem() diff --git a/QuestPDF/Fluent/RowOldExtensions.cs b/QuestPDF/Fluent/RowOldExtensions.cs deleted file mode 100644 index 9104c6f..0000000 --- a/QuestPDF/Fluent/RowOldExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -// using System; -// using QuestPDF.Elements; -// using QuestPDF.Infrastructure; -// -// namespace QuestPDF.Fluent -// { -// public class RowDescriptor -// { -// internal RowOld Row { get; } = new RowOld(); -// -// public void Spacing(float value) -// { -// Row.Spacing = value; -// } -// -// public IContainer ConstantItem(float width) -// { -// return Column(constantWidth: width); -// } -// -// public IContainer RelativeItem(float width = 1) -// { -// return Column(relativeWidth: width); -// } -// -// public IContainer Column(float constantWidth = 0, float relativeWidth = 0) -// { -// var element = new RowOldElement(constantWidth, relativeWidth); -// -// Row.Items.Add(element); -// return element; -// } -// } -// -// public static class RowExtensions -// { -// public static void Row(this IContainer element, Action handler) -// { -// var descriptor = new RowDescriptor(); -// handler(descriptor); -// element.Element(descriptor.Row); -// } -// } -// } \ No newline at end of file diff --git a/QuestPDF/Fluent/TableExtensions.cs b/QuestPDF/Fluent/TableExtensions.cs index e0af338..f345c83 100644 --- a/QuestPDF/Fluent/TableExtensions.cs +++ b/QuestPDF/Fluent/TableExtensions.cs @@ -14,9 +14,9 @@ namespace QuestPDF.Fluent { internal List Columns { get; } = new(); - public void ConstantColumn(float width) + public void ConstantColumn(float width, Unit unit = Unit.Point) { - ComplexColumn(constantWidth: width); + ComplexColumn(constantWidth: width.ToPoints(unit)); } public void RelativeColumn(float width = 1) @@ -24,7 +24,7 @@ namespace QuestPDF.Fluent ComplexColumn(relativeWidth: width); } - public void ComplexColumn(float constantWidth = 0, float relativeWidth = 0) + private void ComplexColumn(float constantWidth = 0, float relativeWidth = 0) { var columnDefinition = new TableColumnDefinition(constantWidth, relativeWidth); Columns.Add(columnDefinition); diff --git a/QuestPDF/Fluent/TextExtensions.cs b/QuestPDF/Fluent/TextExtensions.cs index b4359e5..2d688b4 100644 --- a/QuestPDF/Fluent/TextExtensions.cs +++ b/QuestPDF/Fluent/TextExtensions.cs @@ -37,9 +37,9 @@ namespace QuestPDF.Fluent Alignment = HorizontalAlignment.Right; } - public void ParagraphSpacing(float value) + public void ParagraphSpacing(float value, Unit unit = Unit.Point) { - Spacing = value; + Spacing = value.ToPoints(unit); } private void AddItemToLastTextBlock(ITextBlockItem item) diff --git a/QuestPDF/Fluent/TranslateExtensions.cs b/QuestPDF/Fluent/TranslateExtensions.cs index bb2c148..2e32059 100644 --- a/QuestPDF/Fluent/TranslateExtensions.cs +++ b/QuestPDF/Fluent/TranslateExtensions.cs @@ -14,14 +14,14 @@ namespace QuestPDF.Fluent return element.Element(translate); } - public static IContainer TranslateX(this IContainer element, float value) + public static IContainer TranslateX(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Translate(x => x.TranslateX += value); + return element.Translate(x => x.TranslateX += value.ToPoints(unit)); } - public static IContainer TranslateY(this IContainer element, float value) + public static IContainer TranslateY(this IContainer element, float value, Unit unit = Unit.Point) { - return element.Translate(x => x.TranslateY += value); + return element.Translate(x => x.TranslateY += value.ToPoints(unit)); } } } \ No newline at end of file diff --git a/QuestPDF/Helpers/PageSizes.cs b/QuestPDF/Helpers/PageSizes.cs index c62e0df..fd52af1 100644 --- a/QuestPDF/Helpers/PageSizes.cs +++ b/QuestPDF/Helpers/PageSizes.cs @@ -8,10 +8,10 @@ namespace QuestPDF.Helpers public readonly float Width; public readonly float Height; - public PageSize(float width, float height) + public PageSize(float width, float height, Unit unit = Unit.Point) { - Width = width; - Height = height; + Width = width.ToPoints(unit); + Height = height.ToPoints(unit); } public static implicit operator Size(PageSize pageSize) => new Size(pageSize.Width, pageSize.Height); diff --git a/QuestPDF/Infrastructure/Unit.cs b/QuestPDF/Infrastructure/Unit.cs new file mode 100644 index 0000000..3d2cf8d --- /dev/null +++ b/QuestPDF/Infrastructure/Unit.cs @@ -0,0 +1,44 @@ +using System; +using static QuestPDF.Infrastructure.Unit; + +namespace QuestPDF.Infrastructure +{ + public enum Unit + { + Point, + + Meter, + Centimetre, + Millimetre, + + Feet, + Inch, + Mill + } + + internal static class UnitExtensions + { + private const float InchToCentimetre = 2.54f; + private const float InchToPoints = 72; + + public static float ToPoints(this float value, Unit unit) + { + return value * GetConversionFactor(); + + float GetConversionFactor() + { + return unit switch + { + Point => 1, + Meter => 100 / InchToCentimetre * InchToPoints, + Centimetre => 1 / InchToCentimetre * InchToPoints, + Millimetre => 10 / InchToCentimetre * InchToPoints, + Feet => 12 * InchToPoints, + Inch => InchToPoints, + Mill => InchToPoints / 1000f, + _ => throw new ArgumentOutOfRangeException(nameof(unit), unit, null) + }; + } + } + } +} \ No newline at end of file From b9fbb9267ff1017d2e17e0738d3f0e3a3500deb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Tue, 18 Jan 2022 23:24:10 +0100 Subject: [PATCH 08/17] Obsolete methods refactorization --- QuestPDF/Elements/RowOld.cs | 179 ------------------------ QuestPDF/Elements/Stack.cs | 145 ------------------- QuestPDF/Fluent/ColumnExtensions.cs | 3 +- QuestPDF/Fluent/DecorationExtensions.cs | 12 +- QuestPDF/Fluent/ElementExtensions.cs | 3 +- QuestPDF/Fluent/RowExtensions.cs | 6 +- 6 files changed, 8 insertions(+), 340 deletions(-) delete mode 100644 QuestPDF/Elements/RowOld.cs delete mode 100644 QuestPDF/Elements/Stack.cs diff --git a/QuestPDF/Elements/RowOld.cs b/QuestPDF/Elements/RowOld.cs deleted file mode 100644 index 7f2776c..0000000 --- a/QuestPDF/Elements/RowOld.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using QuestPDF.Drawing; -using QuestPDF.Infrastructure; - -namespace QuestPDF.Elements -{ - // TODO: remove - internal class RowOldElement : Constrained - { - public float ConstantSize { get; } - public float RelativeSize { get; } - - public RowOldElement(float constantSize, float relativeSize) - { - ConstantSize = constantSize; - RelativeSize = relativeSize; - } - - public void SetWidth(float width) - { - MinWidth = width; - MaxWidth = width; - } - } - - // TODO: remove - internal class BinaryRow : Element, ICacheable, IStateResettable - { - internal Element Left { get; set; } - internal Element Right { get; set; } - - private bool IsLeftRendered { get; set; } - private bool IsRightRendered { get; set; } - - public void ResetState() - { - IsLeftRendered = false; - IsRightRendered = false; - } - - internal override IEnumerable GetChildren() - { - yield return Left; - yield return Right; - } - - internal override void CreateProxy(Func create) - { - Left = create(Left); - Right = create(Right); - } - - internal override SpacePlan Measure(Size availableSpace) - { - var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height)); - - 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); - - var targetSize = new Size(totalWidth, totalHeight); - - if ((!IsLeftRendered && leftMeasurement.Type == SpacePlanType.PartialRender) || - (!IsRightRendered && rightMeasurement.Type == SpacePlanType.PartialRender)) - return SpacePlan.PartialRender(targetSize); - - return SpacePlan.FullRender(targetSize); - } - - internal override void Draw(Size availableSpace) - { - var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height)); - var leftWidth = leftMeasurement.Width; - - Left.Draw(new Size(leftWidth, availableSpace.Height)); - - Canvas.Translate(new Position(leftWidth, 0)); - Right.Draw(new Size(availableSpace.Width - leftWidth, availableSpace.Height)); - Canvas.Translate(new Position(-leftWidth, 0)); - } - } - - // TODO: remove - internal class RowOld : Element - { - public float Spacing { get; set; } = 0; - - public ICollection Items { get; internal set; } = new List(); - private Element? RootElement { get; set; } - - internal override IEnumerable GetChildren() - { - if (RootElement == null) - ComposeTree(); - - yield return RootElement; - } - - internal override SpacePlan Measure(Size availableSpace) - { - UpdateElementsWidth(availableSpace.Width); - return RootElement.Measure(availableSpace); - } - - internal override void Draw(Size availableSpace) - { - UpdateElementsWidth(availableSpace.Width); - RootElement.Draw(availableSpace); - } - - #region structure - - private void ComposeTree() - { - Items = AddSpacing(Items, Spacing); - - var elements = Items.Cast().ToArray(); - RootElement = BuildTree(elements); - } - - private void UpdateElementsWidth(float availableWidth) - { - var constantWidth = Items.Sum(x => x.ConstantSize); - var relativeWidth = Items.Sum(x => x.RelativeSize); - - var widthPerRelativeUnit = (relativeWidth > 0) ? (availableWidth - constantWidth) / relativeWidth : 0; - - foreach (var row in Items) - { - row.SetWidth(row.ConstantSize + row.RelativeSize * widthPerRelativeUnit); - } - } - - private static ICollection AddSpacing(ICollection elements, float spacing) - { - if (spacing < Size.Epsilon) - return elements; - - return elements - .SelectMany(x => new[] { new RowOldElement(spacing, 0), x }) - .Skip(1) - .ToList(); - } - - private static Element BuildTree(Span elements) - { - if (elements.IsEmpty) - return Empty.Instance; - - if (elements.Length == 1) - return elements[0]; - - var half = elements.Length / 2; - - return new BinaryRow - { - Left = BuildTree(elements.Slice(0, half)), - Right = BuildTree(elements.Slice(half)) - }; - } - - #endregion - } -} \ No newline at end of file diff --git a/QuestPDF/Elements/Stack.cs b/QuestPDF/Elements/Stack.cs deleted file mode 100644 index e72864f..0000000 --- a/QuestPDF/Elements/Stack.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using QuestPDF.Drawing; -using QuestPDF.Fluent; -using QuestPDF.Infrastructure; -using IComponent = QuestPDF.Infrastructure.IComponent; -using IContainer = QuestPDF.Infrastructure.IContainer; - -namespace QuestPDF.Elements -{ - // TODO: remove - internal class Binarycolumn : Element, IStateResettable, ICacheable - { - internal Element First { get; set; } = Empty.Instance; - internal Element Second { get; set; } = Empty.Instance; - - internal bool IsFirstRendered { get; set; } = false; - - internal override IEnumerable GetChildren() - { - yield return First; - yield return Second; - } - - public void ResetState() - { - IsFirstRendered = false; - } - - internal override void CreateProxy(Func create) - { - First = create(First); - Second = create(Second); - } - - internal override SpacePlan Measure(Size availableSpace) - { - var firstElement = IsFirstRendered ? Empty.Instance : First; - var firstSize = firstElement.Measure(availableSpace); - - if (firstSize.Type == SpacePlanType.Wrap) - return SpacePlan.Wrap(); - - if (firstSize.Type == SpacePlanType.PartialRender) - return firstSize; - - var spaceForSecond = new Size(availableSpace.Width, availableSpace.Height - firstSize.Height); - var secondSize = Second.Measure(spaceForSecond); - - if (secondSize.Type == SpacePlanType.Wrap) - return SpacePlan.PartialRender(firstSize); - - var totalWidth = Math.Max(firstSize.Width, secondSize.Width); - var totalHeight = firstSize.Height + secondSize.Height; - var targetSize = new Size(totalWidth, totalHeight); - - if (secondSize.Type == SpacePlanType.PartialRender) - return SpacePlan.PartialRender(targetSize); - - return SpacePlan.FullRender(targetSize); - } - - internal override void Draw(Size availableSpace) - { - var firstElement = IsFirstRendered ? Empty.Instance : First; - - var firstMeasurement = firstElement.Measure(availableSpace); - - if (firstMeasurement.Type == SpacePlanType.FullRender) - IsFirstRendered = true; - - var firstSize = firstMeasurement; - - if (firstSize.Type != SpacePlanType.Wrap) - firstElement.Draw(new Size(availableSpace.Width, firstSize.Height)); - - if (firstMeasurement.Type == SpacePlanType.Wrap || firstMeasurement.Type == SpacePlanType.PartialRender) - return; - - var firstHeight = firstSize.Height; - var spaceForSecond = new Size(availableSpace.Width, availableSpace.Height - firstHeight); - var secondMeasurement = Second.Measure(spaceForSecond); - - if (secondMeasurement.Type == SpacePlanType.Wrap) - return; - - Canvas.Translate(new Position(0, firstHeight)); - Second.Draw(new Size(availableSpace.Width, secondMeasurement.Height)); - Canvas.Translate(new Position(0, -firstHeight)); - - if (secondMeasurement.Type == SpacePlanType.FullRender) - IsFirstRendered = false; - } - } - - // TODO: remove - internal class column : IComponent - { - public ICollection Items { get; } = new List(); - public float Spacing { get; set; } = 0; - - public void Compose(IContainer container) - { - var elements = AddSpacing(Spacing, Items); - - container - .PaddingBottom(-Spacing) - .Element(BuildTree(elements.ToArray())); - } - - static ICollection AddSpacing(float spacing, ICollection elements) - { - if (spacing < Size.Epsilon) - return elements; - - return elements - .Where(x => !(x is Empty)) - .Select(x => new Padding - { - Bottom = spacing, - Child = x - }) - .Cast() - .ToList(); - } - - static Element BuildTree(Span elements) - { - if (elements.IsEmpty) - return Empty.Instance; - - if (elements.Length == 1) - return elements[0]; - - var half = elements.Length / 2; - - return new Binarycolumn - { - First = BuildTree(elements.Slice(0, half)), - Second = BuildTree(elements.Slice(half)) - }; - } - } -} \ No newline at end of file diff --git a/QuestPDF/Fluent/ColumnExtensions.cs b/QuestPDF/Fluent/ColumnExtensions.cs index a16a299..9c10b20 100644 --- a/QuestPDF/Fluent/ColumnExtensions.cs +++ b/QuestPDF/Fluent/ColumnExtensions.cs @@ -28,8 +28,7 @@ namespace QuestPDF.Fluent public static class ColumnExtensions { - // TODO: deprecated Box method in QuestPDF 2022.2 - [Obsolete("This element has been renamed. Please use the Column method.")] + [Obsolete("This element has been renamed since version 2022.2. Please use the 'Column' method.")] public static void Stack(this IContainer element, Action handler) { element.Column(handler); diff --git a/QuestPDF/Fluent/DecorationExtensions.cs b/QuestPDF/Fluent/DecorationExtensions.cs index 6be4fbe..97a4428 100644 --- a/QuestPDF/Fluent/DecorationExtensions.cs +++ b/QuestPDF/Fluent/DecorationExtensions.cs @@ -46,8 +46,7 @@ namespace QuestPDF.Fluent #region Obsolete - // TODO: deprecated Box method in QuestPDF 2022.2 - [Obsolete("This element has been renamed. Please use the Before method.")] + [Obsolete("This element has been renamed since version 2022.2. Please use the 'Before' method.")] public IContainer Header() { var container = new Container(); @@ -55,15 +54,13 @@ namespace QuestPDF.Fluent return container; } - // TODO: deprecated Box method in QuestPDF 2022.2 - [Obsolete("This element has been renamed. Please use the Before method.")] + [Obsolete("This element has been renamed since version 2022.2. Please use the 'Before' method.")] public void Header(Action handler) { handler?.Invoke(Header()); } - // TODO: deprecated Box method in QuestPDF 2022.2 - [Obsolete("This element has been renamed. Please use the After method.")] + [Obsolete("This element has been renamed since version 2022.2. Please use the 'After' method.")] public IContainer Footer() { var container = new Container(); @@ -71,8 +68,7 @@ namespace QuestPDF.Fluent return container; } - // TODO: deprecated Box method in QuestPDF 2022.2 - [Obsolete("This element has been renamed. Please use the After method.")] + [Obsolete("This element has been renamed since version 2022.2. Please use the 'After' method.")] public void Footer(Action handler) { handler?.Invoke(Footer()); diff --git a/QuestPDF/Fluent/ElementExtensions.cs b/QuestPDF/Fluent/ElementExtensions.cs index 8ac8271..38f5cc5 100644 --- a/QuestPDF/Fluent/ElementExtensions.cs +++ b/QuestPDF/Fluent/ElementExtensions.cs @@ -136,8 +136,7 @@ namespace QuestPDF.Fluent }); } - // TODO: deprecated Box method in QuestPDF 2022.1 - [Obsolete("This element has been renamed. Please use the MinimalBox method.")] + [Obsolete("This element has been renamed since version 2022.1. Please use the MinimalBox method.")] public static IContainer Box(this IContainer element) { return element.Element(new MinimalBox()); diff --git a/QuestPDF/Fluent/RowExtensions.cs b/QuestPDF/Fluent/RowExtensions.cs index 2968eef..2aa5f69 100644 --- a/QuestPDF/Fluent/RowExtensions.cs +++ b/QuestPDF/Fluent/RowExtensions.cs @@ -25,15 +25,13 @@ namespace QuestPDF.Fluent return element; } - // TODO: deprecated Box method in QuestPDF 2022.2 - [Obsolete("This element has been renamed. Please use the RelativeItem method.")] + [Obsolete("This element has been renamed since version 2022.2. Please use the RelativeItem method.")] public IContainer RelativeColumn(float size = 1) { return Item(RowItemType.Relative, size); } - // TODO: deprecated Box method in QuestPDF 2022.2 - [Obsolete("This element has been renamed. Please use the ConstantItem method.")] + [Obsolete("This element has been renamed since version 2022.2. Please use the ConstantItem method.")] public IContainer ConstantColumn(float size) { return Item(RowItemType.Constant, size); From b96c67a8afe525273fd6545356ff3c5d5a3bbbed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Fri, 21 Jan 2022 00:09:39 +0100 Subject: [PATCH 09/17] Fixed Column tests --- .../{StackTests.cs => ColumnTests.cs} | 219 +++++------------- QuestPDF/Elements/Column.cs | 4 +- 2 files changed, 57 insertions(+), 166 deletions(-) rename QuestPDF.UnitTests/{StackTests.cs => ColumnTests.cs} (52%) diff --git a/QuestPDF.UnitTests/StackTests.cs b/QuestPDF.UnitTests/ColumnTests.cs similarity index 52% rename from QuestPDF.UnitTests/StackTests.cs rename to QuestPDF.UnitTests/ColumnTests.cs index bbc1058..694b908 100644 --- a/QuestPDF.UnitTests/StackTests.cs +++ b/QuestPDF.UnitTests/ColumnTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using System.Linq; +using NUnit.Framework; using QuestPDF.Drawing; using QuestPDF.Elements; using QuestPDF.Fluent; @@ -8,19 +9,40 @@ using QuestPDF.UnitTests.TestEngine; namespace QuestPDF.UnitTests { [TestFixture] - public class columnTests + public class ColumnTests { #region Measure + private Column CreateColumnWithTwoItems(TestPlan testPlan) + { + return new Column + { + Items = + { + new ColumnItem + { + Child = testPlan.CreateChild("first") + }, + new ColumnItem + { + Child = testPlan.CreateChild("second") + } + } + }; + } + + private Column CreateColumnWithTwoItemsWhereFirstIsFullyRendered(TestPlan testPlan) + { + var column = CreateColumnWithTwoItems(testPlan); + column.Items.First().IsRendered = true; + return column; + } + [Test] public void Measure_ReturnsWrap_WhenFirstChildWraps() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .MeasureElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap()) .CheckMeasureResult(SpacePlan.Wrap()); @@ -30,11 +52,7 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsPartialRender_WhenFirstChildReturnsPartialRender() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .MeasureElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.PartialRender(300, 200)) .CheckMeasureResult(SpacePlan.PartialRender(300, 200)); @@ -44,11 +62,7 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsPartialRender_WhenSecondChildWraps() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .MeasureElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100)) .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap()) @@ -59,11 +73,7 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsPartialRender_WhenSecondChildReturnsPartialRender() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .MeasureElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100)) .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.PartialRender(300, 150)) @@ -74,33 +84,13 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsFullRender_WhenSecondChildReturnsFullRender() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .MeasureElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100)) .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.FullRender(100, 50)) .CheckMeasureResult(SpacePlan.FullRender(200, 150)); } - - [Test] - public void Measure_UsesEmpty_WhenFirstChildIsRendered() - { - TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second"), - - IsFirstRendered = true - }) - .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("second", new Size(400, 300), SpacePlan.FullRender(200, 300)) - .CheckMeasureResult(SpacePlan.FullRender(200, 300)); - } - + #endregion #region Draw @@ -109,11 +99,7 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildWraps() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .DrawElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.Wrap()) .CheckDrawResult(); @@ -123,14 +109,12 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildPartiallyRenders() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .DrawElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.PartialRender(200, 100)) + .ExpectCanvasTranslate(0, 0) .ExpectChildDraw("first", new Size(400, 100)) + .ExpectCanvasTranslate(0, 0) .CheckDrawResult(); } @@ -138,15 +122,13 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildFullyRenders_AndSecondChildWraps() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .DrawElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100)) - .ExpectChildDraw("first", new Size(400, 100)) .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.Wrap()) + .ExpectCanvasTranslate(0, 0) + .ExpectChildDraw("first", new Size(400, 100)) + .ExpectCanvasTranslate(0, 0) .CheckDrawResult(); } @@ -154,15 +136,13 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildFullyRenders_AndSecondChildPartiallyRenders() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .DrawElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100)) - .ExpectChildDraw("first", new Size(400, 100)) .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.PartialRender(250, 150)) + .ExpectCanvasTranslate(0, 0) + .ExpectChildDraw("first", new Size(400, 100)) + .ExpectCanvasTranslate(0, 0) .ExpectCanvasTranslate(0, 100) .ExpectChildDraw("second", new Size(400, 150)) .ExpectCanvasTranslate(0, -100) @@ -173,15 +153,13 @@ namespace QuestPDF.UnitTests public void Draw_WhenFirstChildFullyRenders_AndSecondChildFullyRenders() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second") - }) + .For(CreateColumnWithTwoItems) .DrawElement(new Size(400, 300)) .ExpectChildMeasure("first", new Size(400, 300), SpacePlan.FullRender(200, 100)) - .ExpectChildDraw("first", new Size(400, 100)) .ExpectChildMeasure("second", new Size(400, 200), SpacePlan.FullRender(250, 150)) + .ExpectCanvasTranslate(0, 0) + .ExpectChildDraw("first", new Size(400, 100)) + .ExpectCanvasTranslate(0, 0) .ExpectCanvasTranslate(0, 100) .ExpectChildDraw("second", new Size(400, 150)) .ExpectCanvasTranslate(0, -100) @@ -192,19 +170,13 @@ namespace QuestPDF.UnitTests public void Draw_UsesEmpty_WhenFirstChildIsRendered() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second"), - - IsFirstRendered = true - }) + .For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered) .DrawElement(new Size(400, 300)) .ExpectChildMeasure("second", new Size(400, 300), SpacePlan.PartialRender(200, 300)) .ExpectCanvasTranslate(0, 0) .ExpectChildDraw("second", new Size(400, 300)) .ExpectCanvasTranslate(0, 0) - .CheckState(x => x.IsFirstRendered) + .CheckState(x => x.Items.First().IsRendered) .CheckDrawResult(); } @@ -212,97 +184,14 @@ namespace QuestPDF.UnitTests public void Draw_TogglesFirstRenderedFlag_WhenSecondFullyRenders() { TestPlan - .For(x => new Binarycolumn - { - First = x.CreateChild("first"), - Second = x.CreateChild("second"), - - IsFirstRendered = true - }) + .For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered) .DrawElement(new Size(400, 300)) .ExpectChildMeasure("second", new Size(400, 300), SpacePlan.FullRender(200, 300)) .ExpectCanvasTranslate(0, 0) .ExpectChildDraw("second", new Size(400, 300)) .ExpectCanvasTranslate(0, 0) .CheckDrawResult() - .CheckState(x => !x.IsFirstRendered); - } - - #endregion - - #region Structure - - [Test] - public void Structure_Simple() - { - // arrange - var childA = TestPlan.CreateUniqueElement(); - var childB = TestPlan.CreateUniqueElement(); - var childC = TestPlan.CreateUniqueElement(); - var childD = TestPlan.CreateUniqueElement(); - var childE = TestPlan.CreateUniqueElement(); - - const int spacing = 20; - - // act - var structure = new Container(); - - structure.Column(column => - { - column.Spacing(spacing); - - column.Item().Element(childA); - column.Item().Element(childB); - column.Item().Element(childC); - column.Item().Element(childD); - column.Item().Element(childE); - }); - - // assert - var expected = new Padding - { - Bottom = -spacing, - - Child = new Binarycolumn - { - First = new Binarycolumn - { - First = new Padding - { - Bottom = spacing, - Child = childA - }, - Second = new Padding - { - Bottom = spacing, - Child = childB - } - }, - Second = new Binarycolumn - { - First = new Padding - { - Bottom = spacing, - Child = childC - }, - Second = new Binarycolumn - { - First = new Padding - { - Bottom = spacing, - Child = childD - }, - Second = new Padding - { - Bottom = spacing, - Child = childE - } - } - } - } - }; - - TestPlan.CompareOperations(structure, expected); + .CheckState(x => !x.Items.First().IsRendered); } #endregion diff --git a/QuestPDF/Elements/Column.cs b/QuestPDF/Elements/Column.cs index 8fad0f1..da42e96 100644 --- a/QuestPDF/Elements/Column.cs +++ b/QuestPDF/Elements/Column.cs @@ -70,8 +70,10 @@ namespace QuestPDF.Elements if (command.Measurement.Type == SpacePlanType.FullRender) command.ColumnItem.IsRendered = true; + var targetSize = new Size(availableSpace.Width, command.Size.Height); + Canvas.Translate(command.Offset); - command.ColumnItem.Draw(command.Size); + command.ColumnItem.Draw(targetSize); Canvas.Translate(command.Offset.Reverse()); } From 3f3ada6d8a83c81a1cfaa98277e8db9815bc0cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Sun, 23 Jan 2022 21:41:45 +0100 Subject: [PATCH 10/17] Minor code adjustments --- QuestPDF.UnitTests/ColumnTests.cs | 4 +- QuestPDF.UnitTests/RowTests.cs | 267 ----------------------------- QuestPDF/Elements/Decoration.cs | 2 +- QuestPDF/Elements/DecorationOld.cs | 101 ----------- QuestPDF/Elements/Row.cs | 8 +- 5 files changed, 7 insertions(+), 375 deletions(-) delete mode 100644 QuestPDF.UnitTests/RowTests.cs delete mode 100644 QuestPDF/Elements/DecorationOld.cs diff --git a/QuestPDF.UnitTests/ColumnTests.cs b/QuestPDF.UnitTests/ColumnTests.cs index 694b908..5ea4af3 100644 --- a/QuestPDF.UnitTests/ColumnTests.cs +++ b/QuestPDF.UnitTests/ColumnTests.cs @@ -11,8 +11,6 @@ namespace QuestPDF.UnitTests [TestFixture] public class ColumnTests { - #region Measure - private Column CreateColumnWithTwoItems(TestPlan testPlan) { return new Column @@ -38,6 +36,8 @@ namespace QuestPDF.UnitTests return column; } + #region Measure + [Test] public void Measure_ReturnsWrap_WhenFirstChildWraps() { diff --git a/QuestPDF.UnitTests/RowTests.cs b/QuestPDF.UnitTests/RowTests.cs deleted file mode 100644 index c2d9925..0000000 --- a/QuestPDF.UnitTests/RowTests.cs +++ /dev/null @@ -1,267 +0,0 @@ -using NUnit.Framework; -using QuestPDF.Drawing; -using QuestPDF.Elements; -using QuestPDF.Fluent; -using QuestPDF.Infrastructure; -using QuestPDF.UnitTests.TestEngine; - -namespace QuestPDF.UnitTests -{ - [TestFixture] - public class RowTests - { - #region Measure - - [Test] - public void Measure_ReturnsWrap_WhenLeftChildReturnsWrap() - { - TestPlan - .For(x => new BinaryRow - { - Left = x.CreateChild("left"), - Right = x.CreateChild("right") - }) - .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.Wrap()) - .CheckMeasureResult(SpacePlan.Wrap()); - } - - [Test] - public void Measure_ReturnsWrap_WhenRightChildReturnsWrap() - { - TestPlan - .For(x => new BinaryRow - { - Left = x.CreateChild("left"), - Right = x.CreateChild("right") - }) - .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150)) - .ExpectChildMeasure("right", new Size(150, 300), SpacePlan.Wrap()) - .CheckMeasureResult(SpacePlan.Wrap()); - } - - [Test] - public void Measure_ReturnsPartialRender_WhenLeftChildReturnsPartialRender() - { - TestPlan - .For(x => new BinaryRow - { - Left = x.CreateChild("left"), - Right = x.CreateChild("right") - }) - .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.PartialRender(250, 150)) - .ExpectChildMeasure("right", new Size(150, 300), SpacePlan.FullRender(100, 100)) - .CheckMeasureResult(SpacePlan.PartialRender(350, 150)); - } - - [Test] - public void Measure_ReturnsPartialRender_WhenRightChildReturnsPartialRender() - { - TestPlan - .For(x => new BinaryRow - { - Left = x.CreateChild("left"), - Right = x.CreateChild("right") - }) - .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150)) - .ExpectChildMeasure("right", new Size(150, 300), SpacePlan.PartialRender(100, 100)) - .CheckMeasureResult(SpacePlan.PartialRender(350, 150)); - } - - [Test] - public void Measure_ReturnsFullRender_WhenBothChildrenReturnFullRender() - { - TestPlan - .For(x => new BinaryRow - { - Left = x.CreateChild("left"), - Right = x.CreateChild("right") - }) - .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(200, 150)) - .ExpectChildMeasure("right", new Size(200, 300), SpacePlan.FullRender(100, 100)) - .CheckMeasureResult(SpacePlan.FullRender(300, 150)); - } - - #endregion - - #region Draw - - [Test] - public void Draw() - { - TestPlan - .For(x => new BinaryRow - { - Left = x.CreateChild("left"), - Right = x.CreateChild("right") - }) - .DrawElement(new Size(400, 300)) - .ExpectChildMeasure("left", new Size(400, 300), SpacePlan.FullRender(250, 150)) - .ExpectChildDraw("left", new Size(250, 300)) - .ExpectCanvasTranslate(250, 0) - .ExpectChildDraw("right", new Size(150, 300)) - .ExpectCanvasTranslate(-250, 0) - .CheckDrawResult(); - } - - #endregion - - #region Structure - - [Test] - public void Structure_RelativeColumnsHandling() - { - // arrange - var childA = TestPlan.CreateUniqueElement(); - var childB = TestPlan.CreateUniqueElement(); - var childC = TestPlan.CreateUniqueElement(); - var childD = TestPlan.CreateUniqueElement(); - var childE = TestPlan.CreateUniqueElement(); - - const int spacing = 25; - var availableSpace = new Size(1100, 400); - - // act - var value = new Container(); - - value.Row(row => - { - row.Spacing(spacing); - - row.ConstantItem(150).Element(childA); - row.ConstantItem(250).Element(childB); - row.RelativeItem(1).Element(childC); - row.RelativeItem(2).Element(childD); - row.RelativeItem(3).Element(childE); - }); - - // assert - var expected = new Container(); - - expected.Row(row => - { - row.Spacing(spacing); - - row.ConstantItem(150).Element(childA); - row.ConstantItem(250).Element(childB); - row.ConstantItem(100).Element(childC); - row.ConstantItem(200).Element(childD); - row.ConstantItem(300).Element(childE); - }); - - TestPlan.CompareOperations(value, expected, availableSpace); - } - - [Test] - public void Structure_Tree() - { - // arrange - var childA = TestPlan.CreateUniqueElement(); - var childB = TestPlan.CreateUniqueElement(); - var childC = TestPlan.CreateUniqueElement(); - var childD = TestPlan.CreateUniqueElement(); - var childE = TestPlan.CreateUniqueElement(); - - const int spacing = 25; - var availableSpace = new Size(1200, 400); - - // act - var value = new Container(); - - value.Row(row => - { - row.Spacing(spacing); - - row.ConstantItem(150).Element(childA); - row.ConstantItem(200).Element(childB); - row.ConstantItem(250).Element(childC); - row.RelativeItem(2).Element(childD); - row.RelativeItem(3).Element(childE); - }); - - // assert - var expected = new BinaryRow - { - Left = new BinaryRow - { - Left = new BinaryRow - { - Left = new Constrained - { - MinWidth = 150, - MaxWidth = 150, - Child = childA - }, - Right = new Constrained - { - MinWidth = 25, - MaxWidth = 25 - } - }, - Right = new BinaryRow - { - Left = new Constrained - { - MinWidth = 200, - MaxWidth = 200, - Child = childB - }, - Right = new Constrained - { - MinWidth = 25, - MaxWidth = 25 - } - } - }, - Right = new BinaryRow - { - Left = new BinaryRow - { - Left = new Constrained - { - MinWidth = 250, - MaxWidth = 250, - Child = childC - }, - Right = new Constrained - { - MinWidth = 25, - MaxWidth = 25 - } - }, - Right = new BinaryRow - { - Left = new Constrained - { - MinWidth = 200, - MaxWidth = 200, - Child = childD - }, - Right = new BinaryRow - { - Left = new Constrained - { - MinWidth = 25, - MaxWidth = 25 - }, - Right = new Constrained - { - MinWidth = 300, - MaxWidth = 300, - Child = childE - } - } - } - } - }; - - TestPlan.CompareOperations(value, expected, availableSpace); - } - - #endregion - } -} \ No newline at end of file diff --git a/QuestPDF/Elements/Decoration.cs b/QuestPDF/Elements/Decoration.cs index 12e9646..c1beb80 100644 --- a/QuestPDF/Elements/Decoration.cs +++ b/QuestPDF/Elements/Decoration.cs @@ -37,7 +37,7 @@ namespace QuestPDF.Elements internal override SpacePlan Measure(Size availableSpace) { - var renderingCommands = PlanLayout(availableSpace); + var renderingCommands = PlanLayout(availableSpace).ToList(); if (renderingCommands.Any(x => x.Measurement.Type == SpacePlanType.Wrap)) return SpacePlan.Wrap(); diff --git a/QuestPDF/Elements/DecorationOld.cs b/QuestPDF/Elements/DecorationOld.cs deleted file mode 100644 index c41c8c7..0000000 --- a/QuestPDF/Elements/DecorationOld.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Collections.Generic; -using QuestPDF.Drawing; -using QuestPDF.Fluent; -using QuestPDF.Infrastructure; - -namespace QuestPDF.Elements -{ - // TODO: remove - internal enum DecorationType - { - Prepend, - Append - } - - // TODO: remove - internal class BinaryDecoration : Element, ICacheable - { - public Element DecorationElement { get; set; } = Empty.Instance; - public Element ContentElement { get; set; } = Empty.Instance; - public DecorationType Type { get; set; } - - internal override IEnumerable GetChildren() - { - yield return DecorationElement; - yield return ContentElement; - } - - internal override void CreateProxy(Func create) - { - DecorationElement = create(DecorationElement); - ContentElement = create(ContentElement); - } - - internal override SpacePlan Measure(Size availableSpace) - { - var decorationMeasure = DecorationElement.Measure(availableSpace); - - if (decorationMeasure.Type == SpacePlanType.Wrap || decorationMeasure.Type == SpacePlanType.PartialRender) - return SpacePlan.Wrap(); - - var decorationSize = decorationMeasure; - var contentMeasure = ContentElement.Measure(new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height)); - - if (contentMeasure.Type == SpacePlanType.Wrap) - return SpacePlan.Wrap(); - - var contentSize = contentMeasure; - var resultSize = new Size(availableSpace.Width, decorationSize.Height + contentSize.Height); - - if (contentSize.Type == SpacePlanType.PartialRender) - return SpacePlan.PartialRender(resultSize); - - if (contentSize.Type == SpacePlanType.FullRender) - return SpacePlan.FullRender(resultSize); - - throw new NotSupportedException(); - } - - internal override void Draw(Size availableSpace) - { - var decorationSize = DecorationElement.Measure(availableSpace); - var contentSize = new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height); - - var translateHeight = Type == DecorationType.Prepend ? decorationSize.Height : contentSize.Height; - Action drawDecoration = () => DecorationElement?.Draw(new Size(availableSpace.Width, decorationSize.Height)); - Action drawContent = () => ContentElement?.Draw(new Size (availableSpace.Width, contentSize.Height)); - - var first = Type == DecorationType.Prepend ? drawDecoration : drawContent; - var second = Type == DecorationType.Prepend ? drawContent : drawDecoration; - - first(); - Canvas.Translate(new Position(0, translateHeight)); - second(); - Canvas.Translate(new Position(0, -translateHeight)); - } - } - - // TODO: remove - internal class DecorationOld : IComponent - { - public Element Header { get; set; } = Empty.Instance; - public Element Content { get; set; } = Empty.Instance; - public Element Footer { get; set; } = Empty.Instance; - - public void Compose(IContainer container) - { - container.Element(new BinaryDecoration - { - Type = DecorationType.Prepend, - DecorationElement = Header, - ContentElement = new BinaryDecoration - { - Type = DecorationType.Append, - ContentElement = Content, - DecorationElement = Footer - } - }); - } - } -} \ No newline at end of file diff --git a/QuestPDF/Elements/Row.cs b/QuestPDF/Elements/Row.cs index ffc157d..3323d72 100644 --- a/QuestPDF/Elements/Row.cs +++ b/QuestPDF/Elements/Row.cs @@ -109,7 +109,7 @@ namespace QuestPDF.Elements return; var widthPerRelativeUnit = (availableWidth - constantWidth - spacingWidth) / relativeWidth; - + foreach (var item in Items.Where(x => x.Type == RowItemType.Relative)) item.Width = item.Size * widthPerRelativeUnit; } @@ -146,12 +146,12 @@ namespace QuestPDF.Elements var rowHeight = renderingCommands.Where(x => !x.RowItem.IsRendered).Max(x => x.Measurement.Height); - renderingCommands.ForEach(command => + foreach (var command in renderingCommands) { command.Size = new Size(command.Size.Width, rowHeight); command.Measurement = command.RowItem.Measure(command.Size); - }); - + } + return renderingCommands; } } From 49a3371af7daa52b8e164c9652331da680736825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Sun, 23 Jan 2022 21:42:03 +0100 Subject: [PATCH 11/17] Added StopPaging element --- QuestPDF/Elements/StopPaging.cs | 25 +++++++++++++++++++++++++ QuestPDF/Fluent/ElementExtensions.cs | 5 +++++ 2 files changed, 30 insertions(+) create mode 100644 QuestPDF/Elements/StopPaging.cs diff --git a/QuestPDF/Elements/StopPaging.cs b/QuestPDF/Elements/StopPaging.cs new file mode 100644 index 0000000..aadb319 --- /dev/null +++ b/QuestPDF/Elements/StopPaging.cs @@ -0,0 +1,25 @@ +using System; +using QuestPDF.Drawing; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Elements +{ + internal class StopPaging : ContainerElement + { + internal override SpacePlan Measure(Size availableSpace) + { + if (Child == null) + return SpacePlan.FullRender(Size.Zero); + + var measurement = Child.Measure(availableSpace); + + return measurement.Type switch + { + SpacePlanType.Wrap => SpacePlan.FullRender(Size.Zero), + SpacePlanType.PartialRender => SpacePlan.FullRender(measurement), + SpacePlanType.FullRender => measurement, + _ => throw new ArgumentOutOfRangeException() + }; + } + } +} \ No newline at end of file diff --git a/QuestPDF/Fluent/ElementExtensions.cs b/QuestPDF/Fluent/ElementExtensions.cs index 38f5cc5..d9ce5fb 100644 --- a/QuestPDF/Fluent/ElementExtensions.cs +++ b/QuestPDF/Fluent/ElementExtensions.cs @@ -160,6 +160,11 @@ namespace QuestPDF.Fluent }); } + public static IContainer StopPaging(this IContainer element) + { + return element.Element(new StopPaging()); + } + public static IContainer ScaleToFit(this IContainer element) { return element.Element(new ScaleToFit()); From 2ca6d1cb47631b57c82bebf1a9f003ec5b332b57 Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Sun, 23 Jan 2022 23:08:18 +0100 Subject: [PATCH 12/17] Decoration: improved implementation, fixed unit tests --- QuestPDF.UnitTests/DecorationTests.cs | 163 +++++++++++++------------- QuestPDF/Elements/Decoration.cs | 30 +++-- 2 files changed, 103 insertions(+), 90 deletions(-) diff --git a/QuestPDF.UnitTests/DecorationTests.cs b/QuestPDF.UnitTests/DecorationTests.cs index b1ea8b4..6f481fc 100644 --- a/QuestPDF.UnitTests/DecorationTests.cs +++ b/QuestPDF.UnitTests/DecorationTests.cs @@ -9,35 +9,27 @@ namespace QuestPDF.UnitTests [TestFixture] public class DecorationTests { + private Decoration CreateDecoration(TestPlan testPlan) + { + return new Decoration + { + Before = testPlan.CreateChild("before"), + Content = testPlan.CreateChild("content"), + After = testPlan.CreateChild("after"), + }; + } + #region Measure [Test] - public void Measure_ReturnsWrap_WhenDecorationReturnsWrap() + public void Measure_ReturnsWrap_WhenBeforeReturnsWrap() { TestPlan - .For(x => new BinaryDecoration - { - Type = DecorationType.Append, - DecorationElement = x.CreateChild("decoration"), - ContentElement = x.CreateChild("content") - }) + .For(CreateDecoration) .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.Wrap()) - .CheckMeasureResult(SpacePlan.Wrap()); - } - - [Test] - public void Measure_ReturnsWrap_WhenDecorationReturnsPartialRender() - { - TestPlan - .For(x => new BinaryDecoration - { - Type = DecorationType.Append, - DecorationElement = x.CreateChild("decoration"), - ContentElement = x.CreateChild("content") - }) - .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.PartialRender(300, 200)) + .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.Wrap()) + .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50)) + .ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100)) .CheckMeasureResult(SpacePlan.Wrap()); } @@ -45,89 +37,100 @@ namespace QuestPDF.UnitTests public void Measure_ReturnsWrap_WhenContentReturnsWrap() { TestPlan - .For(x => new BinaryDecoration - { - Type = DecorationType.Append, - DecorationElement = x.CreateChild("decoration"), - ContentElement = x.CreateChild("content") - }) + .For(CreateDecoration) .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100)) + .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50)) + .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50)) .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.Wrap()) .CheckMeasureResult(SpacePlan.Wrap()); } [Test] - public void Measure_ReturnsPartialRender_WhenContentReturnsPartialRender() + public void Measure_ReturnsWrap_WhenAfterReturnsWrap() { TestPlan - .For(x => new BinaryDecoration - { - Type = DecorationType.Append, - DecorationElement = x.CreateChild("decoration"), - ContentElement = x.CreateChild("content") - }) + .For(CreateDecoration) .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100)) - .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.PartialRender(200, 150)) - .CheckMeasureResult(SpacePlan.PartialRender(400, 250)); + .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50)) + .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.Wrap()) + .ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100)) + .CheckMeasureResult(SpacePlan.Wrap()); } [Test] - public void Measure_ReturnsFullRender_WhenContentReturnsFullRender() + public void Measure_ReturnsWrap_WhenBeforeReturnsPartialRender() { TestPlan - .For(x => new BinaryDecoration - { - Type = DecorationType.Append, - DecorationElement = x.CreateChild("decoration"), - ContentElement = x.CreateChild("content") - }) + .For(CreateDecoration) .MeasureElement(new Size(400, 300)) - .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100)) - .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.FullRender(200, 150)) - .CheckMeasureResult(SpacePlan.FullRender(400, 250)); + .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.PartialRender(100, 50)) + .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50)) + .ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100)) + .CheckMeasureResult(SpacePlan.Wrap()); } + [Test] + public void Measure_ReturnsWrap_WhenAfterReturnsPartialRender() + { + TestPlan + .For(CreateDecoration) + .MeasureElement(new Size(400, 300)) + .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50)) + .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.PartialRender(100, 50)) + .ExpectChildMeasure("content", new Size(400, 250), SpacePlan.FullRender(100, 100)) + .CheckMeasureResult(SpacePlan.Wrap()); + } + + [Test] + public void Measure_ReturnsWrap_WhenContentReturnsPartialRender() + { + TestPlan + .For(CreateDecoration) + .MeasureElement(new Size(400, 300)) + .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50)) + .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50)) + .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.PartialRender(150, 100)) + .CheckMeasureResult(SpacePlan.PartialRender(150, 200)); + } + + [Test] + public void Measure_ReturnsWrap_WhenContentReturnsFullRender() + { + TestPlan + .For(CreateDecoration) + .MeasureElement(new Size(400, 300)) + .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(100, 50)) + .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(100, 50)) + .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.FullRender(150, 100)) + .CheckMeasureResult(SpacePlan.FullRender(150, 200)); + } + #endregion #region Draw - [Test] - public void Draw_Prepend() - { - TestPlan - .For(x => new BinaryDecoration - { - Type = DecorationType.Prepend, - DecorationElement = x.CreateChild("decoration"), - ContentElement = x.CreateChild("content") - }) - .DrawElement(new Size(400, 300)) - .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100)) - .ExpectChildDraw("decoration", new Size(400, 100)) - .ExpectCanvasTranslate(0, 100) - .ExpectChildDraw("content", new Size(400, 200)) - .ExpectCanvasTranslate(0, -100) - .CheckDrawResult(); - } - [Test] public void Draw_Append() { TestPlan - .For(x => new BinaryDecoration - { - Type = DecorationType.Append, - DecorationElement = x.CreateChild("decoration"), - ContentElement = x.CreateChild("content") - }) + .For(CreateDecoration) .DrawElement(new Size(400, 300)) - .ExpectChildMeasure("decoration", new Size(400, 300), SpacePlan.FullRender(300, 100)) - .ExpectChildDraw("content", new Size(400, 200)) - .ExpectCanvasTranslate(0, 200) - .ExpectChildDraw("decoration", new Size(400, 100)) - .ExpectCanvasTranslate(0, -200) + .ExpectChildMeasure("before", new Size(400, 300), SpacePlan.FullRender(200, 40)) + .ExpectChildMeasure("after", new Size(400, 300), SpacePlan.FullRender(200, 60)) + .ExpectChildMeasure("content", new Size(400, 200), SpacePlan.FullRender(300, 100)) + + .ExpectCanvasTranslate(0, 0) + .ExpectChildDraw("before", new Size(300, 40)) + .ExpectCanvasTranslate(0, 0) + + .ExpectCanvasTranslate(0, 40) + .ExpectChildDraw("content", new Size(300, 100)) + .ExpectCanvasTranslate(0, -40) + + .ExpectCanvasTranslate(0, 140) + .ExpectChildDraw("after", new Size(300, 60)) + .ExpectCanvasTranslate(0, -140) + .CheckDrawResult(); } diff --git a/QuestPDF/Elements/Decoration.cs b/QuestPDF/Elements/Decoration.cs index c1beb80..61d72e6 100644 --- a/QuestPDF/Elements/Decoration.cs +++ b/QuestPDF/Elements/Decoration.cs @@ -11,7 +11,6 @@ namespace QuestPDF.Elements { public Element Element { get; set; } public SpacePlan Measurement { get; set; } - public Size Size { get; set; } public Position Offset { get; set; } } @@ -42,8 +41,8 @@ namespace QuestPDF.Elements if (renderingCommands.Any(x => x.Measurement.Type == SpacePlanType.Wrap)) return SpacePlan.Wrap(); - var width = renderingCommands.Max(x => x.Size.Width); - var height = renderingCommands.Sum(x => x.Size.Height); + var width = renderingCommands.Max(x => x.Measurement.Width); + var height = renderingCommands.Sum(x => x.Measurement.Height); var size = new Size(width, height); if (width > availableSpace.Width + Size.Epsilon || height > availableSpace.Height + Size.Epsilon) @@ -58,18 +57,32 @@ namespace QuestPDF.Elements internal override void Draw(Size availableSpace) { - foreach (var command in PlanLayout(availableSpace)) + var renderingCommands = PlanLayout(availableSpace).ToList(); + var width = renderingCommands.Max(x => x.Measurement.Width); + + foreach (var command in renderingCommands) { + var elementSize = new Size(width, command.Measurement.Height); + Canvas.Translate(command.Offset); - command.Element.Draw(command.Size); + command.Element.Draw(elementSize); Canvas.Translate(command.Offset.Reverse()); } } private IEnumerable PlanLayout(Size availableSpace) { - var beforeMeasurement = Before.Measure(availableSpace); - var afterMeasurement = After.Measure(availableSpace); + SpacePlan GetDecorationMeasurement(Element element) + { + var measurement = element.Measure(availableSpace); + + return measurement.Type == SpacePlanType.FullRender + ? measurement + : SpacePlan.Wrap(); + } + + var beforeMeasurement = GetDecorationMeasurement(Before); + var afterMeasurement = GetDecorationMeasurement(After); var contentSpace = new Size(availableSpace.Width, availableSpace.Height - beforeMeasurement.Height - afterMeasurement.Height); var contentMeasurement = Content.Measure(contentSpace); @@ -78,7 +91,6 @@ namespace QuestPDF.Elements { Element = Before, Measurement = beforeMeasurement, - Size = new Size(availableSpace.Width, beforeMeasurement.Height), Offset = Position.Zero }; @@ -86,7 +98,6 @@ namespace QuestPDF.Elements { Element = Content, Measurement = contentMeasurement, - Size = new Size(availableSpace.Width, contentMeasurement.Height), Offset = new Position(0, beforeMeasurement.Height) }; @@ -94,7 +105,6 @@ namespace QuestPDF.Elements { Element = After, Measurement = afterMeasurement, - Size = new Size(availableSpace.Width, afterMeasurement.Height), Offset = new Position(0, beforeMeasurement.Height + contentMeasurement.Height) }; } From 946fe91a98cb2cd6a0bf9375b335dd5af01a46fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Mon, 24 Jan 2022 00:34:27 +0100 Subject: [PATCH 13/17] WriteOnlyStream refactorization --- QuestPDF/Drawing/DocumentGenerator.cs | 6 ++- QuestPDF/Drawing/PdfCanvas.cs | 2 +- QuestPDF/Drawing/XpsCanvas.cs | 2 +- QuestPDF/Helpers/WriteOnlyStream.cs | 56 ++++++++++++++++++++++++++ QuestPDF/Helpers/WriteStreamWrapper.cs | 53 ------------------------ 5 files changed, 62 insertions(+), 57 deletions(-) create mode 100644 QuestPDF/Helpers/WriteOnlyStream.cs delete mode 100644 QuestPDF/Helpers/WriteStreamWrapper.cs diff --git a/QuestPDF/Drawing/DocumentGenerator.cs b/QuestPDF/Drawing/DocumentGenerator.cs index f4d455c..e253c94 100644 --- a/QuestPDF/Drawing/DocumentGenerator.cs +++ b/QuestPDF/Drawing/DocumentGenerator.cs @@ -18,14 +18,16 @@ namespace QuestPDF.Drawing internal static void GeneratePdf(Stream stream, IDocument document) { var metadata = document.GetMetadata(); - var canvas = new PdfCanvas(stream, metadata); + var writeOnlyStream = new WriteOnlyStream(stream); + var canvas = new PdfCanvas(writeOnlyStream, metadata); RenderDocument(canvas, document); } internal static void GenerateXps(Stream stream, IDocument document) { var metadata = document.GetMetadata(); - var canvas = new XpsCanvas(stream, metadata); + var writeOnlyStream = new WriteOnlyStream(stream); + var canvas = new XpsCanvas(writeOnlyStream, metadata); RenderDocument(canvas, document); } diff --git a/QuestPDF/Drawing/PdfCanvas.cs b/QuestPDF/Drawing/PdfCanvas.cs index ca7cf6b..ac703eb 100644 --- a/QuestPDF/Drawing/PdfCanvas.cs +++ b/QuestPDF/Drawing/PdfCanvas.cs @@ -7,7 +7,7 @@ namespace QuestPDF.Drawing internal class PdfCanvas : SkiaDocumentCanvasBase { public PdfCanvas(Stream stream, DocumentMetadata documentMetadata) - : base(SKDocument.CreatePdf(new WriteStreamWrapper(stream), MapMetadata(documentMetadata))) + : base(SKDocument.CreatePdf(stream, MapMetadata(documentMetadata))) { } diff --git a/QuestPDF/Drawing/XpsCanvas.cs b/QuestPDF/Drawing/XpsCanvas.cs index 044f5bf..2c3f65e 100644 --- a/QuestPDF/Drawing/XpsCanvas.cs +++ b/QuestPDF/Drawing/XpsCanvas.cs @@ -7,7 +7,7 @@ namespace QuestPDF.Drawing internal class XpsCanvas : SkiaDocumentCanvasBase { public XpsCanvas(Stream stream, DocumentMetadata documentMetadata) - : base(SKDocument.CreateXps(new WriteStreamWrapper(stream), documentMetadata.RasterDpi)) + : base(SKDocument.CreateXps(stream, documentMetadata.RasterDpi)) { } diff --git a/QuestPDF/Helpers/WriteOnlyStream.cs b/QuestPDF/Helpers/WriteOnlyStream.cs new file mode 100644 index 0000000..e0c4343 --- /dev/null +++ b/QuestPDF/Helpers/WriteOnlyStream.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; + +namespace QuestPDF.Helpers +{ + /// + /// SkiaSharp calls the Position property when generating target document file. + /// If the output stream does not support the Position property, the NullReferenceException is thrown. + /// This wrapper fixes this issue by providing cached Position value (always the end of the stream / current length). + /// Example stream affected: HttpContext.Response.Body + /// + internal class WriteOnlyStream : Stream + { + private readonly Stream InnerStream; + private long StreamLength { get; set; } + + public WriteOnlyStream(Stream stream) + { + if (!stream.CanWrite) + throw new NotSupportedException("Stream cannot be written"); + + InnerStream = stream; + } + + public override bool CanRead => false; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => StreamLength; + + public override long Position + { + get => StreamLength; + set => throw new NotImplementedException(); + } + + public override void Flush() => InnerStream.Flush(); + + public override int Read(byte[] buffer, int offset, int count) + => throw new NotImplementedException(); + + public override long Seek(long offset, SeekOrigin origin) + => throw new NotImplementedException(); + + public override void SetLength(long value) + => throw new NotImplementedException(); + + public override void Write(byte[] buffer, int offset, int count) + { + InnerStream.Write(buffer, offset, count); + StreamLength += count; + } + } +} diff --git a/QuestPDF/Helpers/WriteStreamWrapper.cs b/QuestPDF/Helpers/WriteStreamWrapper.cs deleted file mode 100644 index e4ce5c9..0000000 --- a/QuestPDF/Helpers/WriteStreamWrapper.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.IO; - -namespace QuestPDF.Helpers -{ - internal class WriteStreamWrapper : Stream - { - private readonly Stream _innerStream; - - private long _length; - - public WriteStreamWrapper(Stream stream) - { - if (!stream.CanWrite) - { - throw new NotSupportedException("Stream cannot be written"); - } - - _innerStream = stream; - } - - public override bool CanRead => false; - - public override bool CanSeek => false; - - public override bool CanWrite => true; - - public override long Length => _length; - - public override long Position { - get => _length; - set => throw new NotImplementedException(); - } - - public override void Flush() - => _innerStream.Flush(); - - public override int Read(byte[] buffer, int offset, int count) - => throw new NotImplementedException(); - - public override long Seek(long offset, SeekOrigin origin) - => throw new NotImplementedException(); - - public override void SetLength(long value) - => throw new NotImplementedException(); - - public override void Write(byte[] buffer, int offset, int count) - { - _innerStream.Write(buffer, offset, count); - _length += count; - } - } -} From 5424d9f0a0dd4b71d9d0edc132a8ad2b4240f8c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Mon, 24 Jan 2022 14:53:01 +0100 Subject: [PATCH 14/17] 2022.2.0-beta1 --- QuestPDF.Examples/LineExamples.cs | 10 ++-- QuestPDF/Elements/Inlined.cs | 73 ++++++++++++----------------- QuestPDF/Infrastructure/Size.cs | 4 +- QuestPDF/QuestPDF.csproj | 2 +- QuestPDF/Resources/ReleaseNotes.txt | 8 +++- 5 files changed, 45 insertions(+), 52 deletions(-) diff --git a/QuestPDF.Examples/LineExamples.cs b/QuestPDF.Examples/LineExamples.cs index f9ee753..aa1e141 100644 --- a/QuestPDF.Examples/LineExamples.cs +++ b/QuestPDF.Examples/LineExamples.cs @@ -37,12 +37,12 @@ namespace QuestPDF.Examples .ShowResults() .Render(container => { - container.Padding(25).Row(row => + container.Padding(25).Inlined(inlined => { - row.Spacing(25); - // row.AutoItem().Text("Above text"); - // row.AutoItem().LineVertical(1).LineColor(Colors.Blue.Accent1); - // row.AutoItem().Text("Below text"); + inlined.Spacing(5); + inlined.Item().Text("Above text"); + inlined.Item().LineVertical(1).LineColor(Colors.Blue.Accent1); + inlined.Item().Text("Below text"); }); }); } diff --git a/QuestPDF/Elements/Inlined.cs b/QuestPDF/Elements/Inlined.cs index 9044e6e..8e2aa53 100644 --- a/QuestPDF/Elements/Inlined.cs +++ b/QuestPDF/Elements/Inlined.cs @@ -8,15 +8,7 @@ namespace QuestPDF.Elements { internal class InlinedElement : Container { - public SpacePlan? MeasureCache { get; set; } - internal override SpacePlan Measure(Size availableSpace) - { - // TODO: once element caching proxy is introduces, this can be removed - - MeasureCache ??= Child.Measure(Size.Max); - return MeasureCache.Value; - } } internal enum InlinedAlignment @@ -112,8 +104,11 @@ namespace QuestPDF.Elements foreach (var element in elements) { - var size = element.Measure(Size.Max); + var size = (Size)element.Measure(Size.Max); var baselineOffset = BaselineOffset(size, lineSize.Height); + + if (size.Height == 0) + size = new Size(size.Width, lineSize.Height); Canvas.Translate(new Position(0, baselineOffset)); element.Draw(size); @@ -132,48 +127,39 @@ namespace QuestPDF.Elements if (elements.Count == 1) return 0; - if (ElementsAlignment == InlinedAlignment.Justify) - return difference / (elements.Count - 1); - - if (ElementsAlignment == InlinedAlignment.SpaceAround) - return difference / (elements.Count + 1); - - return HorizontalSpacing; + return ElementsAlignment switch + { + InlinedAlignment.Justify => difference / (elements.Count - 1), + InlinedAlignment.SpaceAround => difference / (elements.Count + 1), + _ => HorizontalSpacing + }; } float AlignOffset() { - if (ElementsAlignment == InlinedAlignment.Left) - return 0; - - if (ElementsAlignment == InlinedAlignment.Justify) - return 0; - - if (ElementsAlignment == InlinedAlignment.SpaceAround) - return elementOffset; - var difference = availableSpace.Width - lineSize.Width - (elements.Count - 1) * HorizontalSpacing; - - if (ElementsAlignment == InlinedAlignment.Center) - return difference / 2; - if (ElementsAlignment == InlinedAlignment.Right) - return difference; - - return 0; + return ElementsAlignment switch + { + InlinedAlignment.Left => 0, + InlinedAlignment.Justify => 0, + InlinedAlignment.SpaceAround => elementOffset, + InlinedAlignment.Center => difference / 2, + InlinedAlignment.Right => difference, + _ => 0 + }; } float BaselineOffset(Size elementSize, float lineHeight) { - if (BaselineAlignment == VerticalAlignment.Top) - return 0; - var difference = lineHeight - elementSize.Height; - - if (BaselineAlignment == VerticalAlignment.Middle) - return difference / 2; - return difference; + return BaselineAlignment switch + { + VerticalAlignment.Top => 0, + VerticalAlignment.Middle => difference / 2, + _ => difference + }; } } } @@ -250,11 +236,12 @@ namespace QuestPDF.Elements float GetInitialAlignmentOffset() { // this method makes sure that the spacing between elements is no lesser than configured - - if (ElementsAlignment == InlinedAlignment.SpaceAround) - return HorizontalSpacing * 2; - return 0; + return ElementsAlignment switch + { + InlinedAlignment.SpaceAround => HorizontalSpacing * 2, + _ => 0 + }; } } } diff --git a/QuestPDF/Infrastructure/Size.cs b/QuestPDF/Infrastructure/Size.cs index 53758a9..bf80b7f 100644 --- a/QuestPDF/Infrastructure/Size.cs +++ b/QuestPDF/Infrastructure/Size.cs @@ -3,13 +3,13 @@ public readonly struct Size { public const float Epsilon = 0.001f; - public const float Infinity = float.PositiveInfinity; + public const float Infinity = 14_400; public readonly float Width; public readonly float Height; public static Size Zero { get; } = new Size(0, 0); - public static Size Max { get; } = new Size(14_400, 14_400); + public static Size Max { get; } = new Size(Infinity, Infinity); public Size(float width, float height) { diff --git a/QuestPDF/QuestPDF.csproj b/QuestPDF/QuestPDF.csproj index 107d1e6..27330a1 100644 --- a/QuestPDF/QuestPDF.csproj +++ b/QuestPDF/QuestPDF.csproj @@ -4,7 +4,7 @@ MarcinZiabek CodeFlint QuestPDF - 2022.1.0-beta4 + 2022.2.0-beta1 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 diff --git a/QuestPDF/Resources/ReleaseNotes.txt b/QuestPDF/Resources/ReleaseNotes.txt index b6a838c..73481bb 100644 --- a/QuestPDF/Resources/ReleaseNotes.txt +++ b/QuestPDF/Resources/ReleaseNotes.txt @@ -1,2 +1,8 @@ - Added a `ScaleToFit` element - scales it child down so it does fit in the provided space, -- Improved default Fluent configuration behavior for elements: Scale, Padding, Translate. \ No newline at end of file +- Added a `StopPaging` element - when its child requires more than one page to fully render, only the first page is shown, +- Added a 'LineVertical' and a 'LineHorizontal' elements - those will simplify your code a lot, no need to use the `Border` element anymore! +- Renaming: the `Stack` element has been renamed to the `Column` element, +- Renaming: children of the `Row` elements are not called `items` instead of `columns`, e.g. `ConstantItem`, `RelativeItem`, `AutoItem`, +- Added support of the `AutoItem` to the `Row` element - those items take as little width as possible, +- Improved default Fluent configuration behavior for elements: Scale, Padding, Translate, +- Improved integration support with the HttpContext.Response.Body. This improvement was introduced by schulz3000, thank you! \ No newline at end of file From 5f7da8b5b3d3dc1a4aa54a4da5ec050ebdd4b99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Wed, 26 Jan 2022 22:26:34 +0100 Subject: [PATCH 15/17] Line: added default configuration --- QuestPDF/Elements/Line.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/QuestPDF/Elements/Line.cs b/QuestPDF/Elements/Line.cs index 0d21d38..03def38 100644 --- a/QuestPDF/Elements/Line.cs +++ b/QuestPDF/Elements/Line.cs @@ -1,4 +1,5 @@ using QuestPDF.Drawing; +using QuestPDF.Helpers; using QuestPDF.Infrastructure; namespace QuestPDF.Elements @@ -16,9 +17,9 @@ namespace QuestPDF.Elements internal class Line : Element, ILine, ICacheable { - public LineType Type { get; set; } - public string Color { get; set; } - public float Size { get; set; } + public LineType Type { get; set; } = LineType.Vertical; + public string Color { get; set; } = Colors.Black; + public float Size { get; set; } = 1; internal override SpacePlan Measure(Size availableSpace) { From ac29ed47943e54710f1da6cb85dad4919f5eb600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Wed, 26 Jan 2022 22:26:47 +0100 Subject: [PATCH 16/17] 2022.2.0-beta2 --- QuestPDF/QuestPDF.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QuestPDF/QuestPDF.csproj b/QuestPDF/QuestPDF.csproj index 27330a1..c9002a6 100644 --- a/QuestPDF/QuestPDF.csproj +++ b/QuestPDF/QuestPDF.csproj @@ -4,7 +4,7 @@ MarcinZiabek CodeFlint QuestPDF - 2022.2.0-beta1 + 2022.2.0-beta2 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 From 9a6b11ab851a967de8a4edf45c36c1f92f607a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Zi=C4=85bek?= Date: Sun, 30 Jan 2022 22:52:56 +0100 Subject: [PATCH 17/17] Updated examples and readme --- QuestPDF.Examples/LineExamples.cs | 37 +++++++++------ QuestPDF.Examples/ScaleToFitExamples.cs | 8 ++-- QuestPDF.Examples/StopPaging.cs | 48 +++++++++++++++++++ QuestPDF/Helpers/Placeholders.cs | 2 +- QuestPDF/QuestPDF.csproj | 2 +- QuestPDF/Resources/ReleaseNotes.txt | 10 ++-- readme.md | 63 ++++++++++++------------- 7 files changed, 112 insertions(+), 58 deletions(-) create mode 100644 QuestPDF.Examples/StopPaging.cs diff --git a/QuestPDF.Examples/LineExamples.cs b/QuestPDF.Examples/LineExamples.cs index aa1e141..7a8852a 100644 --- a/QuestPDF.Examples/LineExamples.cs +++ b/QuestPDF.Examples/LineExamples.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using QuestPDF.Examples.Engine; using QuestPDF.Fluent; using QuestPDF.Helpers; +using QuestPDF.Infrastructure; namespace QuestPDF.Examples { @@ -14,16 +15,20 @@ namespace QuestPDF.Examples RenderingTest .Create() .PageSize(PageSizes.A5) - .ProducePdf() + .ProduceImages() .ShowResults() .Render(container => { - container.Padding(25).Column(column => - { - column.Item().Text("Above text"); - column.Item().PaddingVertical(10).LineHorizontal(1).LineColor(Colors.Blue.Accent1); - column.Item().Text("Below text"); - }); + container + .Padding(15) + .MinimalBox() + .DefaultTextStyle(TextStyle.Default.Size(16)) + .Column(column => + { + column.Item().Text("Above text"); + column.Item().PaddingVertical(5).LineHorizontal(1).LineColor(Colors.Grey.Medium); + column.Item().Text("Below text"); + }); }); } @@ -33,17 +38,19 @@ namespace QuestPDF.Examples RenderingTest .Create() .PageSize(PageSizes.A5) - .ProducePdf() + .ProduceImages() .ShowResults() .Render(container => { - container.Padding(25).Inlined(inlined => - { - inlined.Spacing(5); - inlined.Item().Text("Above text"); - inlined.Item().LineVertical(1).LineColor(Colors.Blue.Accent1); - inlined.Item().Text("Below text"); - }); + container + .Padding(15) + .DefaultTextStyle(TextStyle.Default.Size(16)) + .Row(row => + { + row.AutoItem().Text("Left text"); + row.AutoItem().PaddingHorizontal(10).LineVertical(1).LineColor(Colors.Grey.Medium); + row.AutoItem().Text("Right text"); + }); }); } } diff --git a/QuestPDF.Examples/ScaleToFitExamples.cs b/QuestPDF.Examples/ScaleToFitExamples.cs index f1d714b..b416512 100644 --- a/QuestPDF.Examples/ScaleToFitExamples.cs +++ b/QuestPDF.Examples/ScaleToFitExamples.cs @@ -15,7 +15,7 @@ namespace QuestPDF.Examples RenderingTest .Create() .PageSize(PageSizes.A4) - .ProducePdf() + .ProduceImages() .ShowResults() .Render(container => { @@ -23,15 +23,15 @@ namespace QuestPDF.Examples { var text = Placeholders.Paragraph(); - foreach (var i in Enumerable.Range(0, 16)) + foreach (var i in Enumerable.Range(2, 5)) { column .Item() .MinimalBox() .Border(1) .Padding(5) - .Width(50 + i * 25) - .Height(25 + i * 5) + .Width(i * 40) + .Height(i * 20) .ScaleToFit() .Text(text); } diff --git a/QuestPDF.Examples/StopPaging.cs b/QuestPDF.Examples/StopPaging.cs new file mode 100644 index 0000000..cae0c98 --- /dev/null +++ b/QuestPDF.Examples/StopPaging.cs @@ -0,0 +1,48 @@ +using NUnit.Framework; +using QuestPDF.Examples.Engine; +using QuestPDF.Fluent; +using QuestPDF.Helpers; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Examples +{ + public class StopPaging + { + [Test] + public void Example() + { + RenderingTest + .Create() + .PageSize(300, 250) + .ProduceImages() + .ShowResults() + .Render(container => + { + container + .Padding(25) + .DefaultTextStyle(TextStyle.Default.Size(14)) + .Decoration(decoration => + { + decoration + .Before() + .Text(text => + { + text.DefaultTextStyle(TextStyle.Default.SemiBold().Color(Colors.Blue.Medium)); + + text.Span("Page "); + text.CurrentPageNumber(); + }); + + decoration + .Content() + .Column(column => + { + column.Spacing(25); + column.Item().StopPaging().Text(Placeholders.LoremIpsum()); + column.Item().ExtendHorizontal().Height(75).Background(Colors.Grey.Lighten2); + }); + }); + }); + } + } +} \ No newline at end of file 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/QuestPDF.csproj b/QuestPDF/QuestPDF.csproj index c9002a6..9215d4e 100644 --- a/QuestPDF/QuestPDF.csproj +++ b/QuestPDF/QuestPDF.csproj @@ -4,7 +4,7 @@ MarcinZiabek CodeFlint QuestPDF - 2022.2.0-beta2 + 2022.2.0 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 diff --git a/QuestPDF/Resources/ReleaseNotes.txt b/QuestPDF/Resources/ReleaseNotes.txt index 73481bb..5bcd0ac 100644 --- a/QuestPDF/Resources/ReleaseNotes.txt +++ b/QuestPDF/Resources/ReleaseNotes.txt @@ -1,8 +1,8 @@ -- Added a `ScaleToFit` element - scales it child down so it does fit in the provided space, +- Added a `ScaleToFit` element - scales its child down so it fits in the provided space, - Added a `StopPaging` element - when its child requires more than one page to fully render, only the first page is shown, -- Added a 'LineVertical' and a 'LineHorizontal' elements - those will simplify your code a lot, no need to use the `Border` element anymore! -- Renaming: the `Stack` element has been renamed to the `Column` element, -- Renaming: children of the `Row` elements are not called `items` instead of `columns`, e.g. `ConstantItem`, `RelativeItem`, `AutoItem`, +- Added a 'LineVertical' and a 'LineHorizontal' elements - those will simplify your code a lot, there is no need to use the `Border` element anymore! +- Renaming: the `Stack` element was renamed to the `Column` element, +- Renaming: children of the `Row` element are now called `items` instead of `columns`, e.g. `RelativeItem` instead of `RelativeColumn`, - Added support of the `AutoItem` to the `Row` element - those items take as little width as possible, - Improved default Fluent configuration behavior for elements: Scale, Padding, Translate, -- Improved integration support with the HttpContext.Response.Body. This improvement was introduced by schulz3000, thank you! \ No newline at end of file +- Improved integration support with the HttpContext.Response.Body. This improvement was introduced by schulz3000, thank you! diff --git a/readme.md b/readme.md index 457fe44..3a6b933 100644 --- a/readme.md +++ b/readme.md @@ -149,41 +149,40 @@ void ComposeTable(IContainer container) { var headerStyle = TextStyle.Default.SemiBold(); - container.Decoration(decoration => + container.Table(table => { - // header - decoration.Header().BorderBottom(1).Padding(5).Row(row => + table.ColumnsDefinition(columns => { - row.ConstantColumn(25).Text("#", headerStyle); - row.RelativeColumn(3).Text("Product", headerStyle); - row.RelativeColumn().AlignRight().Text("Unit price", headerStyle); - row.RelativeColumn().AlignRight().Text("Quantity", headerStyle); - row.RelativeColumn().AlignRight().Text("Total", headerStyle); + columns.ConstantColumn(25); + columns.RelativeColumn(3); + columns.RelativeColumn(); + columns.RelativeColumn(); + columns.RelativeColumn(); }); - - // content - decoration - .Content() - .Stack(column => - { - foreach (var item in Model.Items) - { - column - .Item() - .ShowEntire() - .BorderBottom(1) - .BorderColor(Colors.Grey.Lighten2) - .Padding(5) - .Row(row => - { - row.ConstantColumn(25).Text(Model.Items.IndexOf(item) + 1); - row.RelativeColumn(3).Text(item.Name); - row.RelativeColumn().AlignRight().Text($"{item.Price}$"); - row.RelativeColumn().AlignRight().Text(item.Quantity); - row.RelativeColumn().AlignRight().Text($"{item.Price * item.Quantity}$"); - }); - } - }); + + table.Header(header => + { + header.Cell().Text("#", headerStyle); + header.Cell().Text("Product", headerStyle); + header.Cell().AlignRight().Text("Unit price", headerStyle); + header.Cell().AlignRight().Text("Quantity", headerStyle); + header.Cell().AlignRight().Text("Total", headerStyle); + + header.Cell().ColumnSpan(5) + .PaddingVertical(5).BorderBottom(1).BorderColor(Colors.Black); + }); + + foreach (var item in Model.Items) + { + table.Cell().Text(Model.Items.IndexOf(item) + 1); + table.Cell().Text(item.Name); + table.Cell().AlignRight().Text($"{item.Price}$"); + table.Cell().AlignRight().Text(item.Quantity); + table.Cell().AlignRight().Text($"{item.Price * item.Quantity}$"); + + table.Cell().ColumnSpan(5) + .PaddingVertical(5).LineHorizontal(1).LineColor(Colors.Grey.Lighten2); + } }); } ```