Merge remote-tracking branch 'origin/2022.02'
# Conflicts: # QuestPDF.Examples/RowExamples.cs # QuestPDF.UnitTests/RowTests.cs # QuestPDF/Elements/Row.cs # QuestPDF/Fluent/RowExtensions.cs # QuestPDF/QuestPDF.csproj # QuestPDF/Resources/ReleaseNotes.txt
This commit is contained in:
Коммит
3649607bd9
|
@ -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()
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
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(72)
|
||||
.Height(3.5f)
|
||||
.Height(1.5f)
|
||||
.Background(Placeholders.BackgroundColor());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace QuestPDF.Examples
|
|||
public class DebuggingTesting
|
||||
{
|
||||
[Test]
|
||||
public void Stack()
|
||||
public void Column()
|
||||
{
|
||||
Assert.Throws<DocumentLayoutException>(() =>
|
||||
{
|
||||
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -23,21 +23,21 @@ namespace QuestPDF.Examples
|
|||
container.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A6);
|
||||
page.Margin(30);
|
||||
page.Margin(5);
|
||||
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 =>
|
||||
|
|
|
@ -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"));
|
||||
|
@ -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) =>
|
||||
|
@ -501,13 +501,13 @@ namespace QuestPDF.Examples
|
|||
.SemiBold();
|
||||
|
||||
decoration
|
||||
.Header()
|
||||
.Before()
|
||||
.PaddingBottom(10)
|
||||
.Text("Example: scale component", headerFontStyle);
|
||||
|
||||
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");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using QuestPDF.Examples.Engine;
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Examples
|
||||
{
|
||||
public class LineExamples
|
||||
{
|
||||
[Test]
|
||||
public void LineHorizontal()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A5)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
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");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LineVertical()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A5)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
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");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ namespace QuestPDF.Examples
|
|||
container
|
||||
.Background("#FFF")
|
||||
.Padding(25)
|
||||
.Stack(column =>
|
||||
.Column(column =>
|
||||
{
|
||||
column.Spacing(10);
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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.RelativeColumn(3).ValueCell("300px");
|
||||
row.RelativeColumn(1).ValueCell("100px");
|
||||
row.ConstantColumn(50).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");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.Render(container =>
|
||||
{
|
||||
container.Padding(25).Column(column =>
|
||||
{
|
||||
var text = Placeholders.Paragraph();
|
||||
|
||||
foreach (var i in Enumerable.Range(2, 5))
|
||||
{
|
||||
column
|
||||
.Item()
|
||||
.MinimalBox()
|
||||
.Border(1)
|
||||
.Padding(5)
|
||||
.Width(i * 40)
|
||||
.Height(i * 20)
|
||||
.ScaleToFit()
|
||||
.Text(text);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -117,19 +117,19 @@ 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);
|
||||
decoration.After().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)
|
||||
|
|
|
@ -126,7 +126,7 @@ namespace QuestPDF.Examples
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TextStack()
|
||||
public void Textcolumn()
|
||||
{
|
||||
RenderingTest
|
||||
.Create()
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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<ImagePlaceholder>();
|
||||
row.RelativeItem(2).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
|
||||
row.RelativeColumn().PaddingLeft(5).Stack(stack =>
|
||||
row.RelativeItem().PaddingLeft(5).Column(column =>
|
||||
{
|
||||
stack.Spacing(7f);
|
||||
column.Spacing(7f);
|
||||
|
||||
stack.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
stack.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,18 +21,18 @@ namespace QuestPDF.ReportSample.Layouts
|
|||
.Decoration(decoration =>
|
||||
{
|
||||
decoration
|
||||
.Header()
|
||||
.Before()
|
||||
.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);
|
||||
|
@ -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<ImagePlaceholder>();
|
||||
stack.Item().Text(model.Location.Format());
|
||||
column.Item().MaxWidth(250).AspectRatio(4 / 3f).Component<ImagePlaceholder>();
|
||||
column.Item().Text(model.Location.Format());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ImagePlaceholder>();
|
||||
row.RelativeItem().PaddingTop(-10).Text(Model.Title, Typography.Title);
|
||||
row.ConstantItem(90).ExternalLink("https://www.questpdf.com").MaxHeight(30).Component<ImagePlaceholder>();
|
||||
});
|
||||
|
||||
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);
|
||||
column.Spacing(20);
|
||||
|
||||
stack.Item().Component(new TableOfContentsTemplate(Model.Sections));
|
||||
column.Item().Component(new TableOfContentsTemplate(Model.Sections));
|
||||
|
||||
stack.Item().PageBreak();
|
||||
column.Item().PageBreak();
|
||||
|
||||
foreach (var section in Model.Sections)
|
||||
stack.Item().Location(section.Title).Component(new SectionTemplate(section));
|
||||
column.Item().Location(section.Title).Component(new SectionTemplate(section));
|
||||
|
||||
stack.Item().PageBreak();
|
||||
stack.Item().Location("Photos");
|
||||
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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,18 +19,18 @@ namespace QuestPDF.ReportSample.Layouts
|
|||
.Decoration(decoration =>
|
||||
{
|
||||
decoration
|
||||
.Header()
|
||||
.Before()
|
||||
.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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 StackTests
|
||||
public class ColumnTests
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#region Measure
|
||||
|
||||
[Test]
|
||||
public void Measure_ReturnsWrap_WhenFirstChildWraps()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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 BinaryStack
|
||||
{
|
||||
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<BinaryStack>(x => x.IsFirstRendered)
|
||||
.CheckState<Column>(x => x.Items.First().IsRendered)
|
||||
.CheckDrawResult();
|
||||
}
|
||||
|
||||
|
@ -212,97 +184,14 @@ namespace QuestPDF.UnitTests
|
|||
public void Draw_TogglesFirstRenderedFlag_WhenSecondFullyRenders()
|
||||
{
|
||||
TestPlan
|
||||
.For(x => new BinaryStack
|
||||
{
|
||||
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<BinaryStack>(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.Stack(stack =>
|
||||
{
|
||||
stack.Spacing(spacing);
|
||||
|
||||
stack.Item().Element(childA);
|
||||
stack.Item().Element(childB);
|
||||
stack.Item().Element(childC);
|
||||
stack.Item().Element(childD);
|
||||
stack.Item().Element(childE);
|
||||
});
|
||||
|
||||
// assert
|
||||
var expected = new Padding
|
||||
{
|
||||
Bottom = -spacing,
|
||||
|
||||
Child = new BinaryStack
|
||||
{
|
||||
First = new BinaryStack
|
||||
{
|
||||
First = new Padding
|
||||
{
|
||||
Bottom = spacing,
|
||||
Child = childA
|
||||
},
|
||||
Second = new Padding
|
||||
{
|
||||
Bottom = spacing,
|
||||
Child = childB
|
||||
}
|
||||
},
|
||||
Second = new BinaryStack
|
||||
{
|
||||
First = new Padding
|
||||
{
|
||||
Bottom = spacing,
|
||||
Child = childC
|
||||
},
|
||||
Second = new BinaryStack
|
||||
{
|
||||
First = new Padding
|
||||
{
|
||||
Bottom = spacing,
|
||||
Child = childD
|
||||
},
|
||||
Second = new Padding
|
||||
{
|
||||
Bottom = spacing,
|
||||
Child = childE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TestPlan.CompareOperations(structure, expected);
|
||||
.CheckState<Column>(x => !x.Items.First().IsRendered);
|
||||
}
|
||||
|
||||
#endregion
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,268 +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))
|
||||
.ExpectChildMeasure("right", new Size(150, 300), SpacePlan.FullRender(150, 200))
|
||||
.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.ConstantColumn(150).Element(childA);
|
||||
row.ConstantColumn(250).Element(childB);
|
||||
row.RelativeColumn(1).Element(childC);
|
||||
row.RelativeColumn(2).Element(childD);
|
||||
row.RelativeColumn(3).Element(childE);
|
||||
});
|
||||
|
||||
// assert
|
||||
var expected = new Container();
|
||||
|
||||
expected.Row(row =>
|
||||
{
|
||||
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);
|
||||
});
|
||||
|
||||
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.ConstantColumn(150).Element(childA);
|
||||
row.ConstantColumn(200).Element(childB);
|
||||
row.ConstantColumn(250).Element(childC);
|
||||
row.RelativeColumn(2).Element(childD);
|
||||
row.RelativeColumn(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
|
||||
}
|
||||
}
|
|
@ -16,13 +16,13 @@ namespace QuestPDF.Drawing
|
|||
var container = new Container();
|
||||
|
||||
container
|
||||
.Stack(stack =>
|
||||
.Column(column =>
|
||||
{
|
||||
Pages
|
||||
.SelectMany(x => new List<Action>()
|
||||
{
|
||||
() => stack.Item().PageBreak(),
|
||||
() => stack.Item().Component(x)
|
||||
() => column.Item().PageBreak(),
|
||||
() => column.Item().Component(x)
|
||||
})
|
||||
.Skip(1)
|
||||
.ToList()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System.IO;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.Helpers;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Drawing
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System.IO;
|
||||
using QuestPDF.Infrastructure;
|
||||
using QuestPDF.Helpers;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace QuestPDF.Drawing
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
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<ColumnItem> Items { get; } = new();
|
||||
internal float Spacing { get; set; }
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
Items.ForEach(x => x.IsRendered = false);
|
||||
}
|
||||
|
||||
internal override IEnumerable<Element?> GetChildren()
|
||||
{
|
||||
return Items;
|
||||
}
|
||||
|
||||
internal override void CreateProxy(Func<Element?, Element?> 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;
|
||||
|
||||
var targetSize = new Size(availableSpace.Width, command.Size.Height);
|
||||
|
||||
Canvas.Translate(command.Offset);
|
||||
command.ColumnItem.Draw(targetSize);
|
||||
Canvas.Translate(command.Offset.Reverse());
|
||||
}
|
||||
|
||||
if (Items.All(x => x.IsRendered))
|
||||
ResetState();
|
||||
}
|
||||
|
||||
private ICollection<ColumnItemRenderingCommand> PlanLayout(Size availableSpace)
|
||||
{
|
||||
var topOffset = 0f;
|
||||
var commands = new List<ColumnItemRenderingCommand>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,98 +1,112 @@
|
|||
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 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 Before { get; set; } = new Empty();
|
||||
internal Element Content { get; set; } = new Empty();
|
||||
internal Element After { get; set; } = new Empty();
|
||||
|
||||
internal override IEnumerable<Element?> GetChildren()
|
||||
{
|
||||
yield return DecorationElement;
|
||||
yield return ContentElement;
|
||||
yield return Before;
|
||||
yield return Content;
|
||||
yield return After;
|
||||
}
|
||||
|
||||
internal override void CreateProxy(Func<Element, Element> create)
|
||||
internal override void CreateProxy(Func<Element?, Element?> create)
|
||||
{
|
||||
DecorationElement = create(DecorationElement);
|
||||
ContentElement = create(ContentElement);
|
||||
Before = create(Before);
|
||||
Content = create(Content);
|
||||
After = create(After);
|
||||
}
|
||||
|
||||
internal override SpacePlan Measure(Size availableSpace)
|
||||
{
|
||||
var decorationMeasure = DecorationElement.Measure(availableSpace);
|
||||
var renderingCommands = PlanLayout(availableSpace).ToList();
|
||||
|
||||
if (decorationMeasure.Type == SpacePlanType.Wrap || decorationMeasure.Type == SpacePlanType.PartialRender)
|
||||
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.Measurement.Width);
|
||||
var height = renderingCommands.Sum(x => x.Measurement.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 contentSize = contentMeasure;
|
||||
var resultSize = new Size(availableSpace.Width, decorationSize.Height + contentSize.Height);
|
||||
var willBeFullyRendered = renderingCommands.All(x => x.Measurement.Type == SpacePlanType.FullRender);
|
||||
|
||||
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 renderingCommands = PlanLayout(availableSpace).ToList();
|
||||
var width = renderingCommands.Max(x => x.Measurement.Width);
|
||||
|
||||
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
|
||||
foreach (var command in renderingCommands)
|
||||
{
|
||||
public Element Header { get; set; } = Empty.Instance;
|
||||
public Element Content { get; set; } = Empty.Instance;
|
||||
public Element Footer { get; set; } = Empty.Instance;
|
||||
var elementSize = new Size(width, command.Measurement.Height);
|
||||
|
||||
public void Compose(IContainer container)
|
||||
Canvas.Translate(command.Offset);
|
||||
command.Element.Draw(elementSize);
|
||||
Canvas.Translate(command.Offset.Reverse());
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<DecorationItemRenderingCommand> PlanLayout(Size availableSpace)
|
||||
{
|
||||
container.Element(new BinaryDecoration
|
||||
SpacePlan GetDecorationMeasurement(Element element)
|
||||
{
|
||||
Type = DecorationType.Prepend,
|
||||
DecorationElement = Header,
|
||||
ContentElement = new BinaryDecoration
|
||||
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);
|
||||
|
||||
yield return new DecorationItemRenderingCommand
|
||||
{
|
||||
Type = DecorationType.Append,
|
||||
ContentElement = Content,
|
||||
DecorationElement = Footer
|
||||
}
|
||||
});
|
||||
Element = Before,
|
||||
Measurement = beforeMeasurement,
|
||||
Offset = Position.Zero
|
||||
};
|
||||
|
||||
yield return new DecorationItemRenderingCommand
|
||||
{
|
||||
Element = Content,
|
||||
Measurement = contentMeasurement,
|
||||
Offset = new Position(0, beforeMeasurement.Height)
|
||||
};
|
||||
|
||||
yield return new DecorationItemRenderingCommand
|
||||
{
|
||||
Element = After,
|
||||
Measurement = afterMeasurement,
|
||||
Offset = new Position(0, beforeMeasurement.Height + contentMeasurement.Height)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,12 +27,12 @@ namespace QuestPDF.Elements
|
|||
{
|
||||
ChildrenQueue = new Queue<GridElement>(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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,9 +104,12 @@ 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);
|
||||
Canvas.Translate(new Position(0, -baselineOffset));
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -251,10 +237,11 @@ namespace QuestPDF.Elements
|
|||
{
|
||||
// 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
using QuestPDF.Drawing;
|
||||
using QuestPDF.Helpers;
|
||||
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; } = LineType.Vertical;
|
||||
public string Color { get; set; } = Colors.Black;
|
||||
public float Size { get; set; } = 1;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuestPDF.Drawing;
|
||||
|
@ -6,174 +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;
|
||||
Auto,
|
||||
Constant,
|
||||
Relative
|
||||
}
|
||||
|
||||
public void SetWidth(float width)
|
||||
internal class RowItem : Container
|
||||
{
|
||||
MinWidth = width;
|
||||
MaxWidth = width;
|
||||
}
|
||||
public bool IsRendered { get; set; }
|
||||
public float Width { get; set; }
|
||||
|
||||
public RowItemType Type { get; set; }
|
||||
public float Size { get; set; }
|
||||
}
|
||||
|
||||
internal class BinaryRow : Element, ICacheable, IStateResettable
|
||||
internal class RowItemRenderingCommand
|
||||
{
|
||||
internal Element Left { get; set; }
|
||||
internal Element Right { get; set; }
|
||||
public RowItem RowItem { get; set; }
|
||||
public SpacePlan Measurement { get; set; }
|
||||
public Size Size { get; set; }
|
||||
public Position Offset { get; set; }
|
||||
}
|
||||
|
||||
private bool IsLeftRendered { get; set; }
|
||||
private bool IsRightRendered { get; set; }
|
||||
internal class Row : Element, ICacheable, IStateResettable
|
||||
{
|
||||
internal List<RowItem> Items { get; } = new();
|
||||
internal float Spacing { get; set; }
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
IsLeftRendered = false;
|
||||
IsRightRendered = false;
|
||||
Items.ForEach(x => x.IsRendered = false);
|
||||
}
|
||||
|
||||
internal override IEnumerable<Element?> GetChildren()
|
||||
{
|
||||
yield return Left;
|
||||
yield return Right;
|
||||
return Items;
|
||||
}
|
||||
|
||||
internal override void CreateProxy(Func<Element?, Element?> 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));
|
||||
UpdateItemsWidth(availableSpace.Width);
|
||||
var renderingCommands = PlanLayout(availableSpace);
|
||||
|
||||
if (leftMeasurement.Type == SpacePlanType.Wrap)
|
||||
if (renderingCommands.Any(x => !x.RowItem.IsRendered && x.Measurement.Type == SpacePlanType.Wrap))
|
||||
return SpacePlan.Wrap();
|
||||
|
||||
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();
|
||||
|
||||
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 leftSpace = new Size(availableSpace.Width, availableSpace.Height);
|
||||
var leftMeasurement = Left.Measure(leftSpace);
|
||||
UpdateItemsWidth(availableSpace.Width);
|
||||
var renderingCommands = PlanLayout(availableSpace);
|
||||
|
||||
if (leftMeasurement.Type == SpacePlanType.FullRender)
|
||||
IsLeftRendered = true;
|
||||
foreach (var command in renderingCommands)
|
||||
{
|
||||
if (command.Measurement.Type == SpacePlanType.FullRender)
|
||||
command.RowItem.IsRendered = true;
|
||||
|
||||
Left.Draw(new Size(leftMeasurement.Width, availableSpace.Height));
|
||||
if (command.Measurement.Type == SpacePlanType.Wrap)
|
||||
continue;
|
||||
|
||||
var rightSpace = new Size(availableSpace.Width - leftMeasurement.Width, availableSpace.Height);
|
||||
var rightMeasurement = Right.Measure(rightSpace);
|
||||
Canvas.Translate(command.Offset);
|
||||
command.RowItem.Draw(command.Size);
|
||||
Canvas.Translate(command.Offset.Reverse());
|
||||
}
|
||||
|
||||
if (rightMeasurement.Type == SpacePlanType.FullRender)
|
||||
IsRightRendered = true;
|
||||
if (Items.All(x => x.IsRendered))
|
||||
ResetState();
|
||||
}
|
||||
|
||||
Canvas.Translate(new Position(leftMeasurement.Width, 0));
|
||||
Right.Draw(rightSpace);
|
||||
Canvas.Translate(new Position(-leftMeasurement.Width, 0));
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Row : Element
|
||||
private ICollection<RowItemRenderingCommand> PlanLayout(Size availableSpace)
|
||||
{
|
||||
public float Spacing { get; set; } = 0;
|
||||
var leftOffset = 0f;
|
||||
var renderingCommands = new List<RowItemRenderingCommand>();
|
||||
|
||||
public ICollection<RowElement> Items { get; internal set; } = new List<RowElement>();
|
||||
private Element? RootElement { get; set; }
|
||||
|
||||
internal override IEnumerable<Element?> GetChildren()
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (RootElement == null)
|
||||
ComposeTree();
|
||||
var itemSpace = new Size(item.Width, availableSpace.Height);
|
||||
|
||||
yield return RootElement;
|
||||
}
|
||||
|
||||
internal override SpacePlan Measure(Size availableSpace)
|
||||
var command = new RowItemRenderingCommand
|
||||
{
|
||||
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<Element>().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<RowElement> AddSpacing(ICollection<RowElement> elements, float spacing)
|
||||
{
|
||||
if (spacing < Size.Epsilon)
|
||||
return elements;
|
||||
|
||||
return elements
|
||||
.SelectMany(x => new[] { new RowElement(spacing, 0), x })
|
||||
.Skip(1)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static Element BuildTree(Span<Element> 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))
|
||||
RowItem = item,
|
||||
Size = itemSpace,
|
||||
Measurement = item.Measure(itemSpace),
|
||||
Offset = new Position(leftOffset, 0)
|
||||
};
|
||||
|
||||
renderingCommands.Add(command);
|
||||
leftOffset += item.Width + Spacing;
|
||||
}
|
||||
|
||||
#endregion
|
||||
var rowHeight = renderingCommands.Where(x => !x.RowItem.IsRendered).Max(x => x.Measurement.Height);
|
||||
|
||||
foreach (var command in renderingCommands)
|
||||
{
|
||||
command.Size = new Size(command.Size.Width, rowHeight);
|
||||
command.Measurement = command.RowItem.Measure(command.Size);
|
||||
}
|
||||
|
||||
return renderingCommands;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,143 +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
|
||||
{
|
||||
internal class BinaryStack : 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<Element?> GetChildren()
|
||||
{
|
||||
yield return First;
|
||||
yield return Second;
|
||||
}
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
IsFirstRendered = false;
|
||||
}
|
||||
|
||||
internal override void CreateProxy(Func<Element?, Element?> 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;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Stack : IComponent
|
||||
{
|
||||
public ICollection<Element> Items { get; } = new List<Element>();
|
||||
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<Element> AddSpacing(float spacing, ICollection<Element> elements)
|
||||
{
|
||||
if (spacing < Size.Epsilon)
|
||||
return elements;
|
||||
|
||||
return elements
|
||||
.Where(x => !(x is Empty))
|
||||
.Select(x => new Padding
|
||||
{
|
||||
Bottom = spacing,
|
||||
Child = x
|
||||
})
|
||||
.Cast<Element>()
|
||||
.ToList();
|
||||
}
|
||||
|
||||
static Element BuildTree(Span<Element> elements)
|
||||
{
|
||||
if (elements.IsEmpty)
|
||||
return Empty.Instance;
|
||||
|
||||
if (elements.Length == 1)
|
||||
return elements[0];
|
||||
|
||||
var half = elements.Length / 2;
|
||||
|
||||
return new BinaryStack
|
||||
{
|
||||
First = BuildTree(elements.Slice(0, half)),
|
||||
Second = BuildTree(elements.Slice(half))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using QuestPDF.Elements;
|
||||
using QuestPDF.Infrastructure;
|
||||
|
||||
namespace QuestPDF.Fluent
|
||||
{
|
||||
public class ColumnDescriptor
|
||||
{
|
||||
internal Column Column { get; } = new();
|
||||
|
||||
public void Spacing(float value, Unit unit = Unit.Point)
|
||||
{
|
||||
Column.Spacing = value.ToPoints(unit);
|
||||
}
|
||||
|
||||
public IContainer Item()
|
||||
{
|
||||
var container = new Container();
|
||||
|
||||
Column.Items.Add(new ColumnItem
|
||||
{
|
||||
Child = container
|
||||
});
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ColumnExtensions
|
||||
{
|
||||
[Obsolete("This element has been renamed since version 2022.2. Please use the 'Column' method.")]
|
||||
public static void Stack(this IContainer element, Action<ColumnDescriptor> handler)
|
||||
{
|
||||
element.Column(handler);
|
||||
}
|
||||
|
||||
public static void Column(this IContainer element, Action<ColumnDescriptor> handler)
|
||||
{
|
||||
var descriptor = new ColumnDescriptor();
|
||||
handler(descriptor);
|
||||
element.Element(descriptor.Column);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<IContainer> handler)
|
||||
public void Before(Action<IContainer> handler)
|
||||
{
|
||||
handler?.Invoke(Header());
|
||||
handler?.Invoke(Before());
|
||||
}
|
||||
|
||||
public IContainer Content()
|
||||
|
@ -32,17 +32,49 @@ 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 After(Action<IContainer> handler)
|
||||
{
|
||||
handler?.Invoke(After());
|
||||
}
|
||||
|
||||
#region Obsolete
|
||||
|
||||
[Obsolete("This element has been renamed since version 2022.2. Please use the 'Before' method.")]
|
||||
public IContainer Header()
|
||||
{
|
||||
var container = new Container();
|
||||
Decoration.Before = container;
|
||||
return container;
|
||||
}
|
||||
|
||||
[Obsolete("This element has been renamed since version 2022.2. Please use the 'Before' method.")]
|
||||
public void Header(Action<IContainer> handler)
|
||||
{
|
||||
handler?.Invoke(Header());
|
||||
}
|
||||
|
||||
[Obsolete("This element has been renamed since version 2022.2. Please use the 'After' method.")]
|
||||
public IContainer Footer()
|
||||
{
|
||||
var container = new Container();
|
||||
Decoration.After = container;
|
||||
return container;
|
||||
}
|
||||
|
||||
[Obsolete("This element has been renamed since version 2022.2. Please use the 'After' method.")]
|
||||
public void Footer(Action<IContainer> handler)
|
||||
{
|
||||
handler?.Invoke(Footer());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class DecorationExtensions
|
||||
|
@ -52,7 +84,7 @@ namespace QuestPDF.Fluent
|
|||
var descriptor = new DecorationDescriptor();
|
||||
handler(descriptor);
|
||||
|
||||
element.Component(descriptor.Decoration);
|
||||
element.Element(descriptor.Decoration);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
@ -160,5 +159,15 @@ namespace QuestPDF.Fluent
|
|||
TextStyle = textStyle
|
||||
});
|
||||
}
|
||||
|
||||
public static IContainer StopPaging(this IContainer element)
|
||||
{
|
||||
return element.Element(new StopPaging());
|
||||
}
|
||||
|
||||
public static IContainer ScaleToFit(this IContainer element)
|
||||
{
|
||||
return element.Element(new ScaleToFit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, Unit unit = Unit.Point)
|
||||
{
|
||||
return element.Line(LineType.Vertical, size.ToPoints(unit));
|
||||
}
|
||||
|
||||
public static ILine LineHorizontal(this IContainer element, float size, Unit unit = Unit.Point)
|
||||
{
|
||||
return element.Line(LineType.Horizontal, size.ToPoints(unit));
|
||||
}
|
||||
|
||||
public static void LineColor(this ILine descriptor, string value)
|
||||
{
|
||||
(descriptor as Line).Color = value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -6,30 +6,51 @@ 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)
|
||||
var element = new RowItem
|
||||
{
|
||||
return Column(relativeWidth: width);
|
||||
}
|
||||
|
||||
private IContainer Column(float constantWidth = 0, float relativeWidth = 0)
|
||||
{
|
||||
var element = new RowElement(constantWidth, relativeWidth);
|
||||
Type = type,
|
||||
Size = size
|
||||
};
|
||||
|
||||
Row.Items.Add(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
public IContainer RelativeItem(float size = 1)
|
||||
{
|
||||
return Item(RowItemType.Relative, size);
|
||||
}
|
||||
|
||||
public IContainer ConstantItem(float size, Unit unit = Unit.Point)
|
||||
{
|
||||
return Item(RowItemType.Constant, size.ToPoints(unit));
|
||||
}
|
||||
|
||||
public IContainer AutoItem()
|
||||
{
|
||||
return Item(RowItemType.Auto);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RowExtensions
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<StackDescriptor> handler)
|
||||
{
|
||||
var descriptor = new StackDescriptor();
|
||||
handler(descriptor);
|
||||
element.Component(descriptor.Stack);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,9 +14,9 @@ namespace QuestPDF.Fluent
|
|||
{
|
||||
internal List<TableColumnDefinition> 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);
|
||||
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace QuestPDF.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
<Authors>MarcinZiabek</Authors>
|
||||
<Company>CodeFlint</Company>
|
||||
<PackageId>QuestPDF</PackageId>
|
||||
<Version>2022.1.0</Version>
|
||||
<Version>2022.2.0</Version>
|
||||
<PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
|
||||
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt"))</PackageReleaseNotes>
|
||||
<LangVersion>9</LangVersion>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
- 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 😁
|
||||
- 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.
|
||||
- Fixed default page sizes for: Letter and Legal.
|
||||
- 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, 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!
|
||||
|
|
53
readme.md
53
readme.md
|
@ -149,42 +149,41 @@ 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 =>
|
||||
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)
|
||||
{
|
||||
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.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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче