Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 78e5cbd098 | |||
| f792f6c749 | |||
| 0d86039c0c |
@@ -19,20 +19,20 @@ namespace QuestPDF.Examples
|
|||||||
|
|
||||||
//[ShowResult]
|
//[ShowResult]
|
||||||
[ImageSize(300, 300)]
|
[ImageSize(300, 300)]
|
||||||
public void Section(IContainer container)
|
public void Decoration(IContainer container)
|
||||||
{
|
{
|
||||||
container
|
container
|
||||||
.Background("#FFF")
|
.Background("#FFF")
|
||||||
.Padding(25)
|
.Padding(25)
|
||||||
.Decoration(section =>
|
.Decoration(decoration =>
|
||||||
{
|
{
|
||||||
section
|
decoration
|
||||||
.Header()
|
.Header()
|
||||||
.Background("#888")
|
.Background("#888")
|
||||||
.Padding(10)
|
.Padding(10)
|
||||||
.Text("Notes", TextStyle.Default.Size(16).Color("#FFF"));
|
.Text("Notes", TextStyle.Default.Size(16).Color("#FFF"));
|
||||||
|
|
||||||
section
|
decoration
|
||||||
.Content()
|
.Content()
|
||||||
.Background("#DDD")
|
.Background("#DDD")
|
||||||
.Padding(10)
|
.Padding(10)
|
||||||
@@ -181,12 +181,12 @@ namespace QuestPDF.Examples
|
|||||||
grid.Spacing(5);
|
grid.Spacing(5);
|
||||||
grid.Columns(12);
|
grid.Columns(12);
|
||||||
|
|
||||||
grid.Element(8).Background("#DDD").Height(50).Padding(5).Text("This is a short text", textStyle);
|
grid.Item(8).Background("#DDD").Height(50).Padding(5).Text("This is a short text", textStyle);
|
||||||
grid.Element(4).Background("#BBB").Padding(5).Text("Showing how to...", textStyle);
|
grid.Item(4).Background("#BBB").Padding(5).Text("Showing how to...", textStyle);
|
||||||
grid.Element(2).Background("#999").Height(50);
|
grid.Item(2).Background("#999").Height(50);
|
||||||
grid.Element(4).Background("#AAA").Border(2).BorderColor("#666").Padding(5).Text("...generate", textStyle);
|
grid.Item(4).Background("#AAA").Border(2).BorderColor("#666").Padding(5).Text("...generate", textStyle);
|
||||||
grid.Element(6).Background("#CCC").Padding(5).Text("simple grids", textStyle.Size(18).Bold());
|
grid.Item(6).Background("#CCC").Padding(5).Text("simple grids", textStyle.Size(18).Bold());
|
||||||
grid.Element(8).Background("#DDD").Height(50);
|
grid.Item(8).Background("#DDD").Height(50);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ namespace QuestPDF.ReportSample.Layouts
|
|||||||
.Stack(stack =>
|
.Stack(stack =>
|
||||||
{
|
{
|
||||||
stack.Spacing(5);
|
stack.Spacing(5);
|
||||||
stack.Item(PhotoWithMaps);
|
stack.Item().Element(PhotoWithMaps);
|
||||||
stack.Item(PhotoDetails);
|
stack.Item().Element(PhotoDetails);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,13 +48,13 @@ namespace QuestPDF.ReportSample.Layouts
|
|||||||
{
|
{
|
||||||
grid.Columns(6);
|
grid.Columns(6);
|
||||||
|
|
||||||
grid.Element().LabelCell().Text("Date", Typography.Normal);
|
grid.Item().LabelCell().Text("Date", Typography.Normal);
|
||||||
grid.Element(2).ValueCell().Text(Model.Date?.ToString("g") ?? string.Empty, Typography.Normal);
|
grid.Item(2).ValueCell().Text(Model.Date?.ToString("g") ?? string.Empty, Typography.Normal);
|
||||||
grid.Element().LabelCell().Text("Location", Typography.Normal);
|
grid.Item().LabelCell().Text("Location", Typography.Normal);
|
||||||
grid.Element(2).ValueCell().Text(Model.Location.Format(), Typography.Normal);
|
grid.Item(2).ValueCell().Text(Model.Location.Format(), Typography.Normal);
|
||||||
|
|
||||||
grid.Element().LabelCell().Text("Comments", Typography.Normal);
|
grid.Item().LabelCell().Text("Comments", Typography.Normal);
|
||||||
grid.Element(5).ValueCell().Text(Model.Comments, Typography.Normal);
|
grid.Item(5).ValueCell().Text(Model.Comments, Typography.Normal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ namespace QuestPDF.ReportSample.Layouts
|
|||||||
{
|
{
|
||||||
container
|
container
|
||||||
.EnsureSpace()
|
.EnsureSpace()
|
||||||
.Decoration(section =>
|
.Decoration(decoration =>
|
||||||
{
|
{
|
||||||
section
|
decoration
|
||||||
.Header()
|
.Header()
|
||||||
.PaddingBottom(5)
|
.PaddingBottom(5)
|
||||||
.Text(Model.Title, Typography.Headline);
|
.Text(Model.Title, Typography.Headline);
|
||||||
|
|
||||||
section.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Stack(stack =>
|
decoration.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Stack(stack =>
|
||||||
{
|
{
|
||||||
foreach (var part in Model.Parts)
|
foreach (var part in Model.Parts)
|
||||||
{
|
{
|
||||||
@@ -77,7 +77,7 @@ namespace QuestPDF.ReportSample.Layouts
|
|||||||
grid.Spacing(5);
|
grid.Spacing(5);
|
||||||
grid.Columns(3);
|
grid.Columns(3);
|
||||||
|
|
||||||
model.Photos.ForEach(x => grid.Element().AspectRatio(4 / 3f).Image(Placeholders.Image));
|
model.Photos.ForEach(x => grid.Item().AspectRatio(4 / 3f).Image(Placeholders.Image));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ namespace QuestPDF.ReportSample.Layouts
|
|||||||
.PaddingHorizontal(50)
|
.PaddingHorizontal(50)
|
||||||
.Page(page =>
|
.Page(page =>
|
||||||
{
|
{
|
||||||
page.Header(ComposeHeader);
|
page.Header().Element(ComposeHeader);
|
||||||
page.Content(ComposeContent);
|
page.Content().Element(ComposeContent);
|
||||||
page.Footer().AlignCenter().PageNumber("Page {number}");
|
page.Footer().AlignCenter().PageNumber("Page {number}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ namespace QuestPDF.ReportSample.Layouts
|
|||||||
|
|
||||||
foreach (var field in Model.HeaderFields)
|
foreach (var field in Model.HeaderFields)
|
||||||
{
|
{
|
||||||
grid.Element().Stack(row =>
|
grid.Item().Stack(row =>
|
||||||
{
|
{
|
||||||
row.Item().AlignLeft().Text(field.Label, Typography.Normal.SemiBold());
|
row.Item().AlignLeft().Text(field.Label, Typography.Normal.SemiBold());
|
||||||
row.Item().Text(field.Value, Typography.Normal);
|
row.Item().Text(field.Value, Typography.Normal);
|
||||||
|
|||||||
@@ -16,21 +16,21 @@ namespace QuestPDF.ReportSample.Layouts
|
|||||||
public void Compose(IContainer container)
|
public void Compose(IContainer container)
|
||||||
{
|
{
|
||||||
container
|
container
|
||||||
.Decoration(section =>
|
.Decoration(decoration =>
|
||||||
{
|
{
|
||||||
section
|
decoration
|
||||||
.Header()
|
.Header()
|
||||||
.PaddingBottom(5)
|
.PaddingBottom(5)
|
||||||
.Text("Table of contents", Typography.Headline);
|
.Text("Table of contents", Typography.Headline);
|
||||||
|
|
||||||
section.Content().Stack(stack =>
|
decoration.Content().Stack(stack =>
|
||||||
{
|
{
|
||||||
stack.Spacing(5);
|
stack.Spacing(5);
|
||||||
|
|
||||||
for (var i = 0; i < Sections.Count; i++)
|
for (var i = 0; i < Sections.Count; i++)
|
||||||
stack.Item(c => DrawLink(c, i+1, Sections[i].Title));
|
stack.Item().Element(c => DrawLink(c, i+1, Sections[i].Title));
|
||||||
|
|
||||||
stack.Item(c => DrawLink(c, Sections.Count+1, "Photos"));
|
stack.Item().Element(c => DrawLink(c, Sections.Count+1, "Photos"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ using QuestPDF.UnitTests.TestEngine;
|
|||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class WrapWhenLittleSpaceTests
|
public class EnsureSpaceTests
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void Measure_ReturnsWrap_WhenNotEnoughSpace()
|
public void Measure_ReturnsWrap_WhenChildReturnsWrap()
|
||||||
{
|
{
|
||||||
TestPlan
|
TestPlan
|
||||||
.For(x => new EnsureSpace
|
.For(x => new EnsureSpace
|
||||||
@@ -19,11 +19,54 @@ namespace QuestPDF.UnitTests
|
|||||||
MinHeight = 200
|
MinHeight = 200
|
||||||
})
|
})
|
||||||
.MeasureElement(new Size(400, 100))
|
.MeasureElement(new Size(400, 100))
|
||||||
|
.ExpectChildMeasure(new Size(400, 100), new Wrap())
|
||||||
.CheckMeasureResult(new Wrap());
|
.CheckMeasureResult(new Wrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Measure_Continues_WhenEnoughSpace()
|
public void Measure_ReturnsWrap_WhenChildReturnsPartialRender_AndNotEnoughSpace()
|
||||||
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new EnsureSpace
|
||||||
|
{
|
||||||
|
Child = x.CreateChild(),
|
||||||
|
MinHeight = 200
|
||||||
|
})
|
||||||
|
.MeasureElement(new Size(400, 100))
|
||||||
|
.ExpectChildMeasure(new Size(400, 100), new PartialRender(300, 50))
|
||||||
|
.CheckMeasureResult(new Wrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Measure_ReturnsPartialRender_WhenChildReturnsPartialRender_AndEnoughSpace()
|
||||||
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new EnsureSpace
|
||||||
|
{
|
||||||
|
Child = x.CreateChild(),
|
||||||
|
MinHeight = 200
|
||||||
|
})
|
||||||
|
.MeasureElement(new Size(400, 300))
|
||||||
|
.ExpectChildMeasure(new Size(400, 300), new PartialRender(300, 250))
|
||||||
|
.CheckMeasureResult(new PartialRender(300, 250));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Measure_ReturnsFullRender_WhenChildReturnsFullRender_AndNotEnoughSpace()
|
||||||
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new EnsureSpace
|
||||||
|
{
|
||||||
|
Child = x.CreateChild(),
|
||||||
|
MinHeight = 200
|
||||||
|
})
|
||||||
|
.MeasureElement(new Size(400, 100))
|
||||||
|
.ExpectChildMeasure(new Size(400, 100), new FullRender(300, 50))
|
||||||
|
.CheckMeasureResult(new FullRender(300, 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Measure_ReturnsFullRender_WhenChildReturnsFullRender_AndEnoughSpace()
|
||||||
{
|
{
|
||||||
TestPlan
|
TestPlan
|
||||||
.For(x => new EnsureSpace
|
.For(x => new EnsureSpace
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using QuestPDF.UnitTests.TestEngine;
|
|||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
/*[TestFixture]
|
||||||
public class GridTests
|
public class GridTests
|
||||||
{
|
{
|
||||||
#region Alignment
|
#region Alignment
|
||||||
@@ -29,11 +29,11 @@ namespace QuestPDF.UnitTests
|
|||||||
{
|
{
|
||||||
grid.AlignLeft();
|
grid.AlignLeft();
|
||||||
|
|
||||||
grid.Element(6).Element(childA);
|
grid.Item(6).Element(childA);
|
||||||
grid.Element(4).Element(childB);
|
grid.Item(4).Element(childB);
|
||||||
grid.Element(4).Element(childC);
|
grid.Item(4).Element(childC);
|
||||||
grid.Element(2).Element(childD);
|
grid.Item(2).Element(childD);
|
||||||
grid.Element(8).Element(childE);
|
grid.Item(8).Element(childE);
|
||||||
});
|
});
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
@@ -45,20 +45,20 @@ namespace QuestPDF.UnitTests
|
|||||||
{
|
{
|
||||||
row.RelativeColumn(6).Element(childA);
|
row.RelativeColumn(6).Element(childA);
|
||||||
row.RelativeColumn(4).Element(childB);
|
row.RelativeColumn(4).Element(childB);
|
||||||
row.RelativeColumn(2).Element(new Empty());
|
row.RelativeColumn(2).Element(Empty.Instance);
|
||||||
});
|
});
|
||||||
|
|
||||||
stack.Item().Row(row =>
|
stack.Item().Row(row =>
|
||||||
{
|
{
|
||||||
row.RelativeColumn(4).Element(childC);
|
row.RelativeColumn(4).Element(childC);
|
||||||
row.RelativeColumn(2).Element(childD);
|
row.RelativeColumn(2).Element(childD);
|
||||||
row.RelativeColumn(6).Element(new Empty());
|
row.RelativeColumn(6).Element(Empty.Instance);
|
||||||
});
|
});
|
||||||
|
|
||||||
stack.Item().Row(row =>
|
stack.Item().Row(row =>
|
||||||
{
|
{
|
||||||
row.RelativeColumn(8).Element(childE);
|
row.RelativeColumn(8).Element(childE);
|
||||||
row.RelativeColumn(4).Element(new Empty());
|
row.RelativeColumn(4).Element(Empty.Instance);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -83,11 +83,11 @@ namespace QuestPDF.UnitTests
|
|||||||
{
|
{
|
||||||
grid.AlignCenter();
|
grid.AlignCenter();
|
||||||
|
|
||||||
grid.Element(6).Element(childA);
|
grid.Item(6).Element(childA);
|
||||||
grid.Element(4).Element(childB);
|
grid.Item(4).Element(childB);
|
||||||
grid.Element(4).Element(childC);
|
grid.Item(4).Element(childC);
|
||||||
grid.Element(2).Element(childD);
|
grid.Item(2).Element(childD);
|
||||||
grid.Element(8).Element(childE);
|
grid.Item(8).Element(childE);
|
||||||
});
|
});
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
@@ -97,25 +97,25 @@ namespace QuestPDF.UnitTests
|
|||||||
{
|
{
|
||||||
stack.Item().Row(row =>
|
stack.Item().Row(row =>
|
||||||
{
|
{
|
||||||
row.RelativeColumn(1).Element(new Empty());
|
row.RelativeColumn(1).Element(Empty.Instance);
|
||||||
row.RelativeColumn(6).Element(childA);
|
row.RelativeColumn(6).Element(childA);
|
||||||
row.RelativeColumn(4).Element(childB);
|
row.RelativeColumn(4).Element(childB);
|
||||||
row.RelativeColumn(1).Element(new Empty());
|
row.RelativeColumn(1).Element(Empty.Instance);
|
||||||
});
|
});
|
||||||
|
|
||||||
stack.Item().Row(row =>
|
stack.Item().Row(row =>
|
||||||
{
|
{
|
||||||
row.RelativeColumn(3).Element(new Empty());
|
row.RelativeColumn(3).Element(Empty.Instance);
|
||||||
row.RelativeColumn(4).Element(childC);
|
row.RelativeColumn(4).Element(childC);
|
||||||
row.RelativeColumn(2).Element(childD);
|
row.RelativeColumn(2).Element(childD);
|
||||||
row.RelativeColumn(3).Element(new Empty());
|
row.RelativeColumn(3).Element(Empty.Instance);
|
||||||
});
|
});
|
||||||
|
|
||||||
stack.Item().Row(row =>
|
stack.Item().Row(row =>
|
||||||
{
|
{
|
||||||
row.RelativeColumn(2).Element(new Empty());
|
row.RelativeColumn(2).Element(Empty.Instance);
|
||||||
row.RelativeColumn(8).Element(childE);
|
row.RelativeColumn(8).Element(childE);
|
||||||
row.RelativeColumn(2).Element(new Empty());
|
row.RelativeColumn(2).Element(Empty.Instance);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -140,11 +140,11 @@ namespace QuestPDF.UnitTests
|
|||||||
{
|
{
|
||||||
grid.AlignRight();
|
grid.AlignRight();
|
||||||
|
|
||||||
grid.Element(6).Element(childA);
|
grid.Item(6).Element(childA);
|
||||||
grid.Element(4).Element(childB);
|
grid.Item(4).Element(childB);
|
||||||
grid.Element(4).Element(childC);
|
grid.Item(4).Element(childC);
|
||||||
grid.Element(2).Element(childD);
|
grid.Item(2).Element(childD);
|
||||||
grid.Element(8).Element(childE);
|
grid.Item(8).Element(childE);
|
||||||
});
|
});
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
@@ -154,21 +154,21 @@ namespace QuestPDF.UnitTests
|
|||||||
{
|
{
|
||||||
stack.Item().Row(row =>
|
stack.Item().Row(row =>
|
||||||
{
|
{
|
||||||
row.RelativeColumn(2).Element(new Empty());
|
row.RelativeColumn(2).Element(Empty.Instance);
|
||||||
row.RelativeColumn(6).Element(childA);
|
row.RelativeColumn(6).Element(childA);
|
||||||
row.RelativeColumn(4).Element(childB);
|
row.RelativeColumn(4).Element(childB);
|
||||||
});
|
});
|
||||||
|
|
||||||
stack.Item().Row(row =>
|
stack.Item().Row(row =>
|
||||||
{
|
{
|
||||||
row.RelativeColumn(6).Element(new Empty());
|
row.RelativeColumn(6).Element(Empty.Instance);
|
||||||
row.RelativeColumn(4).Element(childC);
|
row.RelativeColumn(4).Element(childC);
|
||||||
row.RelativeColumn(2).Element(childD);
|
row.RelativeColumn(2).Element(childD);
|
||||||
});
|
});
|
||||||
|
|
||||||
stack.Item().Row(row =>
|
stack.Item().Row(row =>
|
||||||
{
|
{
|
||||||
row.RelativeColumn(4).Element(new Empty());
|
row.RelativeColumn(4).Element(Empty.Instance);
|
||||||
row.RelativeColumn(8).Element(childE);
|
row.RelativeColumn(8).Element(childE);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -177,5 +177,5 @@ namespace QuestPDF.UnitTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using NUnit.Framework;
|
||||||
using FluentAssertions;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using NUnit.Framework;
|
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Fluent;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.TestEngine;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
namespace QuestPDF.UnitTests
|
namespace QuestPDF.UnitTests
|
||||||
@@ -10,103 +9,108 @@ namespace QuestPDF.UnitTests
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class RowTests
|
public class RowTests
|
||||||
{
|
{
|
||||||
#region Spacing
|
#region Measure
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Fluent_WithoutSpacing()
|
public void Measure_ReturnsWrap_WhenLeftChildReturnsWrap()
|
||||||
{
|
{
|
||||||
// arrange
|
TestPlan
|
||||||
var structure = new Container();
|
.For(x => new SimpleRow
|
||||||
|
|
||||||
var childA = TestPlan.CreateUniqueElement();
|
|
||||||
var childB = TestPlan.CreateUniqueElement();
|
|
||||||
var childC = TestPlan.CreateUniqueElement();
|
|
||||||
|
|
||||||
// act
|
|
||||||
structure
|
|
||||||
.Row(stack =>
|
|
||||||
{
|
{
|
||||||
stack.Spacing(0);
|
Left = x.CreateChild("left"),
|
||||||
|
Right = x.CreateChild("right")
|
||||||
stack.ConstantColumn(100).Element(childA);
|
})
|
||||||
stack.RelativeColumn(2).Element(childB);
|
.MeasureElement(new Size(400, 300))
|
||||||
stack.RelativeColumn(3).Element(childC);
|
.ExpectChildMeasure("left", new Size(400, 300), new Wrap())
|
||||||
});
|
.CheckMeasureResult(new Wrap());
|
||||||
|
|
||||||
// assert
|
|
||||||
var expected = new Row()
|
|
||||||
{
|
|
||||||
Children = new List<RowElement>
|
|
||||||
{
|
|
||||||
new ConstantRowElement(100)
|
|
||||||
{
|
|
||||||
Child = childA
|
|
||||||
},
|
|
||||||
new RelativeRowElement(2)
|
|
||||||
{
|
|
||||||
Child = childB
|
|
||||||
},
|
|
||||||
new RelativeRowElement(3)
|
|
||||||
{
|
|
||||||
Child = childC
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
structure.Child.Should().BeEquivalentTo(expected, o => o.WithStrictOrdering().IncludingAllRuntimeProperties());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Fluent_WithSpacing()
|
public void Measure_ReturnsWrap_WhenRightChildReturnsWrap()
|
||||||
{
|
{
|
||||||
// arrange
|
TestPlan
|
||||||
var structure = new Container();
|
.For(x => new SimpleRow
|
||||||
|
|
||||||
var childA = TestPlan.CreateUniqueElement();
|
|
||||||
var childB = TestPlan.CreateUniqueElement();
|
|
||||||
var childC = TestPlan.CreateUniqueElement();
|
|
||||||
|
|
||||||
// act
|
|
||||||
structure
|
|
||||||
.Row(stack =>
|
|
||||||
{
|
{
|
||||||
stack.Spacing(25);
|
Left = x.CreateChild("left"),
|
||||||
|
Right = x.CreateChild("right")
|
||||||
stack.ConstantColumn(100).Element(childA);
|
})
|
||||||
stack.RelativeColumn(2).Element(childB);
|
.MeasureElement(new Size(400, 300))
|
||||||
stack.RelativeColumn(3).Element(childC);
|
.ExpectChildMeasure("left", new Size(400, 300), new FullRender(250, 150))
|
||||||
});
|
.ExpectChildMeasure("right", new Size(150, 300), new Wrap())
|
||||||
|
.CheckMeasureResult(new Wrap());
|
||||||
// assert
|
}
|
||||||
var expected = new Padding
|
|
||||||
{
|
[Test]
|
||||||
Right = -25,
|
public void Measure_ReturnsPartialRender_WhenLeftChildReturnsPartialRender()
|
||||||
Child = new Row()
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new SimpleRow
|
||||||
{
|
{
|
||||||
Children = new List<RowElement>
|
Left = x.CreateChild("left"),
|
||||||
{
|
Right = x.CreateChild("right")
|
||||||
new ConstantRowElement(100)
|
})
|
||||||
{
|
.MeasureElement(new Size(400, 300))
|
||||||
Child = childA
|
.ExpectChildMeasure("left", new Size(400, 300), new PartialRender(250, 150))
|
||||||
},
|
.ExpectChildMeasure("right", new Size(150, 300), new FullRender(100, 100))
|
||||||
new ConstantRowElement(25),
|
.CheckMeasureResult(new PartialRender(350, 150));
|
||||||
new RelativeRowElement(2)
|
}
|
||||||
{
|
|
||||||
Child = childB
|
[Test]
|
||||||
},
|
public void Measure_ReturnsPartialRender_WhenRightChildReturnsPartialRender()
|
||||||
new ConstantRowElement(25),
|
{
|
||||||
new RelativeRowElement(3)
|
TestPlan
|
||||||
{
|
.For(x => new SimpleRow
|
||||||
Child = childC
|
{
|
||||||
},
|
Left = x.CreateChild("left"),
|
||||||
new ConstantRowElement(25)
|
Right = x.CreateChild("right")
|
||||||
}
|
})
|
||||||
}
|
.MeasureElement(new Size(400, 300))
|
||||||
};
|
.ExpectChildMeasure("left", new Size(400, 300), new FullRender(250, 150))
|
||||||
|
.ExpectChildMeasure("right", new Size(150, 300), new PartialRender(100, 100))
|
||||||
structure.Child.Should().BeEquivalentTo(expected, o => o.WithStrictOrdering().IncludingAllRuntimeProperties());
|
.CheckMeasureResult(new PartialRender(350, 150));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Measure_ReturnsFullRender_WhenBothChildrenReturnFullRender()
|
||||||
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new SimpleRow
|
||||||
|
{
|
||||||
|
Left = x.CreateChild("left"),
|
||||||
|
Right = x.CreateChild("right")
|
||||||
|
})
|
||||||
|
.MeasureElement(new Size(400, 300))
|
||||||
|
.ExpectChildMeasure("left", new Size(400, 300), new FullRender(200, 150))
|
||||||
|
.ExpectChildMeasure("right", new Size(200, 300), new FullRender(100, 100))
|
||||||
|
.CheckMeasureResult(new FullRender(300, 150));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Draw
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Draw()
|
||||||
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new SimpleRow
|
||||||
|
{
|
||||||
|
Left = x.CreateChild("left"),
|
||||||
|
Right = x.CreateChild("right")
|
||||||
|
})
|
||||||
|
.DrawElement(new Size(400, 300))
|
||||||
|
.ExpectChildMeasure("left", new Size(400, 300), new FullRender(250, 150))
|
||||||
|
.ExpectChildDraw("left", new Size(250, 300))
|
||||||
|
.ExpectCanvasTranslate(250, 0)
|
||||||
|
.ExpectChildDraw("right", new Size(150, 300))
|
||||||
|
.ExpectCanvasTranslate(-250, 0)
|
||||||
|
.CheckDrawResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// TODO: add tests for the spacing property
|
||||||
|
// TODO: add tests for the tree builder method
|
||||||
|
// TODO: add tests for relative column
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+188
-243
@@ -1,9 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using NUnit.Framework;
|
||||||
using FluentAssertions;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Elements;
|
using QuestPDF.Elements;
|
||||||
using QuestPDF.Fluent;
|
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
using QuestPDF.UnitTests.TestEngine;
|
using QuestPDF.UnitTests.TestEngine;
|
||||||
|
|
||||||
@@ -13,278 +10,226 @@ namespace QuestPDF.UnitTests
|
|||||||
public class StackTests
|
public class StackTests
|
||||||
{
|
{
|
||||||
#region Measure
|
#region Measure
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Measure_NoChildren_Empty()
|
public void Measure_ReturnsWrap_WhenFirstChildWraps()
|
||||||
{
|
{
|
||||||
TestPlan
|
TestPlan
|
||||||
.For(x => new Stack())
|
.For(x => new SimpleStack
|
||||||
.MeasureElement(new Size(500, 1000))
|
|
||||||
.CheckMeasureResult(new FullRender(Size.Zero));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Measure_ReturnsWrap_WhenPageable_AndAnyChildReturnsWrap()
|
|
||||||
{
|
|
||||||
TestPlan
|
|
||||||
.For(x => new Stack
|
|
||||||
{
|
{
|
||||||
Children = new []
|
First = x.CreateChild("first"),
|
||||||
{
|
Second = x.CreateChild("second")
|
||||||
x.CreateChild("a"),
|
|
||||||
x.CreateChild("b"),
|
|
||||||
x.CreateChild("c"),
|
|
||||||
x.CreateChild("d")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.MeasureElement(new Size(500, 1000))
|
.MeasureElement(new Size(400, 300))
|
||||||
.ExpectChildMeasure("a", expectedInput: new Size(500, 1000), returns: new FullRender(500, 200))
|
.ExpectChildMeasure("first", new Size(400, 300), new Wrap())
|
||||||
.ExpectChildMeasure("b", expectedInput: new Size(500, 800), returns: new FullRender(500, 300))
|
|
||||||
.ExpectChildMeasure("c", expectedInput: new Size(500, 500), returns: new Wrap())
|
|
||||||
.CheckMeasureResult(new PartialRender(500, 500));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Measure_ReturnsWrap_WhenPageable_AndFirstChildReturnsWrap()
|
|
||||||
{
|
|
||||||
TestPlan
|
|
||||||
.For(x => new Stack
|
|
||||||
{
|
|
||||||
Children = new []
|
|
||||||
{
|
|
||||||
x.CreateChild("a"),
|
|
||||||
x.CreateChild("b"),
|
|
||||||
x.CreateChild("c")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.MeasureElement(new Size(500, 1000))
|
|
||||||
.ExpectChildMeasure("a", expectedInput: new Size(500, 1000), returns: new Wrap())
|
|
||||||
.CheckMeasureResult(new Wrap());
|
.CheckMeasureResult(new Wrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Combined
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void WhenPageable_AndChildReturnsWrap()
|
public void Measure_ReturnsPartialRender_WhenFirstChildReturnsPartialRender()
|
||||||
{
|
{
|
||||||
TestPlan
|
TestPlan
|
||||||
.For(x => new Stack
|
.For(x => new SimpleStack
|
||||||
{
|
{
|
||||||
Children = new[]
|
First = x.CreateChild("first"),
|
||||||
{
|
Second = x.CreateChild("second")
|
||||||
x.CreateChild("a"),
|
|
||||||
x.CreateChild("b"),
|
|
||||||
x.CreateChild("c")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.MeasureElement(new Size(400, 300))
|
||||||
// page 1: measure
|
.ExpectChildMeasure("first", new Size(400, 300), new PartialRender(300, 200))
|
||||||
.MeasureElement(new Size(500, 1000))
|
.CheckMeasureResult(new PartialRender(300, 200));
|
||||||
.ExpectChildMeasure("a", expectedInput: new Size(500, 1000), returns: new FullRender(400, 200))
|
|
||||||
.ExpectChildMeasure("b", expectedInput: new Size(500, 800), returns: new Wrap())
|
|
||||||
.CheckMeasureResult(new PartialRender(500, 200))
|
|
||||||
|
|
||||||
// page 1: draw
|
|
||||||
.DrawElement(new Size(500, 1000))
|
|
||||||
|
|
||||||
.ExpectChildMeasure("a", expectedInput: new Size(500, 1000), returns: new FullRender(400, 200))
|
|
||||||
.ExpectCanvasTranslate(0, 0)
|
|
||||||
.ExpectChildDraw("a", new Size(500, 200))
|
|
||||||
.ExpectCanvasTranslate(0, 0)
|
|
||||||
|
|
||||||
.ExpectChildMeasure("b", expectedInput: new Size(500, 800), returns: new Wrap())
|
|
||||||
|
|
||||||
.CheckDrawResult()
|
|
||||||
|
|
||||||
// // page 2: measure
|
|
||||||
.MeasureElement(new Size(500, 900))
|
|
||||||
.ExpectChildMeasure("b", expectedInput: new Size(500, 900), returns: new FullRender(300, 200))
|
|
||||||
.ExpectChildMeasure("c", expectedInput: new Size(500, 700), returns: new FullRender(300, 300))
|
|
||||||
.CheckMeasureResult(new FullRender(500, 500))
|
|
||||||
|
|
||||||
// page 2: draw
|
|
||||||
.DrawElement(new Size(500, 900))
|
|
||||||
|
|
||||||
.ExpectChildMeasure("b", expectedInput: new Size(500, 900), returns: new FullRender(300, 200))
|
|
||||||
.ExpectCanvasTranslate(0, 0)
|
|
||||||
.ExpectChildDraw("b", new Size(500, 200))
|
|
||||||
.ExpectCanvasTranslate(0, 0)
|
|
||||||
|
|
||||||
.ExpectChildMeasure("c", expectedInput: new Size(500, 700), returns: new FullRender(300, 300))
|
|
||||||
.ExpectCanvasTranslate(0, 200)
|
|
||||||
.ExpectChildDraw("c", new Size(500, 300))
|
|
||||||
.ExpectCanvasTranslate(0, -200)
|
|
||||||
|
|
||||||
.CheckDrawResult();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void WhenPageable_AndChildReturnsPartialRender()
|
public void Measure_ReturnsPartialRender_WhenSecondChildWraps()
|
||||||
{
|
{
|
||||||
TestPlan
|
TestPlan
|
||||||
.For(x => new Stack
|
.For(x => new SimpleStack
|
||||||
{
|
{
|
||||||
Children = new[]
|
First = x.CreateChild("first"),
|
||||||
{
|
Second = x.CreateChild("second")
|
||||||
x.CreateChild("a"),
|
|
||||||
x.CreateChild("b"),
|
|
||||||
x.CreateChild("c")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.MeasureElement(new Size(400, 300))
|
||||||
// page 1: measure
|
.ExpectChildMeasure("first", new Size(400, 300), new FullRender(200, 100))
|
||||||
.MeasureElement(new Size(500, 1000))
|
.ExpectChildMeasure("second", new Size(400, 200), new Wrap())
|
||||||
.ExpectChildMeasure("a", expectedInput: new Size(500, 1000), returns: new FullRender(400, 200))
|
.CheckMeasureResult(new PartialRender(200, 100));
|
||||||
.ExpectChildMeasure("b", expectedInput: new Size(500, 800), returns: new PartialRender(300, 300))
|
}
|
||||||
.CheckMeasureResult(new PartialRender(500, 500))
|
|
||||||
|
[Test]
|
||||||
// page 1: draw
|
public void Measure_ReturnsPartialRender_WhenSecondChildReturnsPartialRender()
|
||||||
.DrawElement(new Size(500, 1000))
|
{
|
||||||
|
TestPlan
|
||||||
.ExpectChildMeasure("a", expectedInput: new Size(500, 1000), returns: new FullRender(400, 200))
|
.For(x => new SimpleStack
|
||||||
.ExpectCanvasTranslate(0, 0)
|
{
|
||||||
.ExpectChildDraw("a", new Size(500, 200))
|
First = x.CreateChild("first"),
|
||||||
.ExpectCanvasTranslate(0, 0)
|
Second = x.CreateChild("second")
|
||||||
|
})
|
||||||
.ExpectChildMeasure("b", expectedInput: new Size(500, 800), returns: new PartialRender(300, 300))
|
.MeasureElement(new Size(400, 300))
|
||||||
.ExpectCanvasTranslate(0, 200)
|
.ExpectChildMeasure("first", new Size(400, 300), new FullRender(200, 100))
|
||||||
.ExpectChildDraw("b", new Size(500, 300))
|
.ExpectChildMeasure("second", new Size(400, 200), new PartialRender(300, 150))
|
||||||
.ExpectCanvasTranslate(0, -200)
|
.CheckMeasureResult(new PartialRender(300, 250));
|
||||||
|
}
|
||||||
.CheckDrawResult()
|
|
||||||
|
[Test]
|
||||||
// page 2: measure
|
public void Measure_ReturnsFullRender_WhenSecondChildReturnsFullRender()
|
||||||
.MeasureElement(new Size(500, 900))
|
{
|
||||||
.ExpectChildMeasure("b", expectedInput: new Size(500, 900), returns: new FullRender(300, 200))
|
TestPlan
|
||||||
.ExpectChildMeasure("c", expectedInput: new Size(500, 700), returns: new FullRender(300, 300))
|
.For(x => new SimpleStack
|
||||||
.CheckMeasureResult(new FullRender(500, 500))
|
{
|
||||||
|
First = x.CreateChild("first"),
|
||||||
// page 2: draw
|
Second = x.CreateChild("second")
|
||||||
.DrawElement(new Size(500, 900))
|
})
|
||||||
|
.MeasureElement(new Size(400, 300))
|
||||||
.ExpectChildMeasure("b", expectedInput: new Size(500, 900), returns: new FullRender(300, 200))
|
.ExpectChildMeasure("first", new Size(400, 300), new FullRender(200, 100))
|
||||||
.ExpectCanvasTranslate(0, 0)
|
.ExpectChildMeasure("second", new Size(400, 200), new FullRender(100, 50))
|
||||||
.ExpectChildDraw("b", new Size(500, 200))
|
.CheckMeasureResult(new FullRender(200, 150));
|
||||||
.ExpectCanvasTranslate(0, 0)
|
}
|
||||||
|
|
||||||
.ExpectChildMeasure("c", expectedInput: new Size(500, 700), returns: new FullRender(300, 300))
|
[Test]
|
||||||
.ExpectCanvasTranslate(0, 200)
|
public void Measure_UsesEmpty_WhenFirstChildIsRendered()
|
||||||
.ExpectChildDraw("c", new Size(500, 300))
|
{
|
||||||
.ExpectCanvasTranslate(0, -200)
|
TestPlan
|
||||||
|
.For(x => new SimpleStack
|
||||||
|
{
|
||||||
|
First = x.CreateChild("first"),
|
||||||
|
Second = x.CreateChild("second"),
|
||||||
|
|
||||||
|
IsFirstRendered = true
|
||||||
|
})
|
||||||
|
.MeasureElement(new Size(400, 300))
|
||||||
|
.ExpectChildMeasure("second", new Size(400, 300), new FullRender(200, 300))
|
||||||
|
.CheckMeasureResult(new FullRender(200, 300));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Draw
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Draw_WhenFirstChildWraps()
|
||||||
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new SimpleStack
|
||||||
|
{
|
||||||
|
First = x.CreateChild("first"),
|
||||||
|
Second = x.CreateChild("second")
|
||||||
|
})
|
||||||
|
.DrawElement(new Size(400, 300))
|
||||||
|
.ExpectChildMeasure("first", new Size(400, 300), new Wrap())
|
||||||
.CheckDrawResult();
|
.CheckDrawResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Spacing
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Fluent_WithoutSpacing()
|
public void Draw_WhenFirstChildPartiallyRenders()
|
||||||
{
|
{
|
||||||
// arrange
|
TestPlan
|
||||||
var structure = new Container();
|
.For(x => new SimpleStack
|
||||||
|
|
||||||
var childA = TestPlan.CreateUniqueElement();
|
|
||||||
var childB = TestPlan.CreateUniqueElement();
|
|
||||||
var childC = TestPlan.CreateUniqueElement();
|
|
||||||
|
|
||||||
// act
|
|
||||||
structure
|
|
||||||
.Stack(stack =>
|
|
||||||
{
|
{
|
||||||
stack.Spacing(0);
|
First = x.CreateChild("first"),
|
||||||
|
Second = x.CreateChild("second")
|
||||||
stack.Item().Element(childA);
|
})
|
||||||
stack.Item().Element(childB);
|
.DrawElement(new Size(400, 300))
|
||||||
stack.Item().Element(childC);
|
.ExpectChildMeasure("first", new Size(400, 300), new PartialRender(200, 100))
|
||||||
});
|
.ExpectChildDraw("first", new Size(400, 100))
|
||||||
|
.CheckDrawResult();
|
||||||
// assert
|
|
||||||
var expected = new Stack
|
|
||||||
{
|
|
||||||
Children = new List<Element>
|
|
||||||
{
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Child = childA
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Child = childB
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Child = childC
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
structure.Child.Should().BeEquivalentTo(expected, o => o.WithStrictOrdering().IncludingAllRuntimeProperties());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Fluent_WithSpacing()
|
public void Draw_WhenFirstChildFullyRenders_AndSecondChildWraps()
|
||||||
{
|
{
|
||||||
// arrange
|
TestPlan
|
||||||
var structure = new Container();
|
.For(x => new SimpleStack
|
||||||
|
|
||||||
var childA = TestPlan.CreateUniqueElement();
|
|
||||||
var childB = TestPlan.CreateUniqueElement();
|
|
||||||
var childC = TestPlan.CreateUniqueElement();
|
|
||||||
|
|
||||||
// act
|
|
||||||
structure
|
|
||||||
.Stack(stack =>
|
|
||||||
{
|
{
|
||||||
stack.Spacing(100);
|
First = x.CreateChild("first"),
|
||||||
|
Second = x.CreateChild("second")
|
||||||
stack.Item().Element(childA);
|
})
|
||||||
stack.Item().Element(childB);
|
.DrawElement(new Size(400, 300))
|
||||||
stack.Item().Element(childC);
|
.ExpectChildMeasure("first", new Size(400, 300), new FullRender(200, 100))
|
||||||
});
|
.ExpectChildDraw("first", new Size(400, 100))
|
||||||
|
.ExpectChildMeasure("second", new Size(400, 200), new Wrap())
|
||||||
// assert
|
.CheckDrawResult();
|
||||||
var expected = new Padding
|
}
|
||||||
{
|
|
||||||
Bottom = -100,
|
[Test]
|
||||||
Child = new Stack
|
public void Draw_WhenFirstChildFullyRenders_AndSecondChildPartiallyRenders()
|
||||||
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new SimpleStack
|
||||||
{
|
{
|
||||||
Children = new List<Element>
|
First = x.CreateChild("first"),
|
||||||
{
|
Second = x.CreateChild("second")
|
||||||
new Padding
|
})
|
||||||
{
|
.DrawElement(new Size(400, 300))
|
||||||
Bottom = 100,
|
.ExpectChildMeasure("first", new Size(400, 300), new FullRender(200, 100))
|
||||||
Child = new Container
|
.ExpectChildDraw("first", new Size(400, 100))
|
||||||
{
|
.ExpectChildMeasure("second", new Size(400, 200), new PartialRender(250, 150))
|
||||||
Child = childA
|
.ExpectCanvasTranslate(0, 100)
|
||||||
}
|
.ExpectChildDraw("second", new Size(400, 150))
|
||||||
},
|
.ExpectCanvasTranslate(0, -100)
|
||||||
new Padding
|
.CheckDrawResult();
|
||||||
{
|
}
|
||||||
Bottom = 100,
|
|
||||||
Child = new Container
|
[Test]
|
||||||
{
|
public void Draw_WhenFirstChildFullyRenders_AndSecondChildFullyRenders()
|
||||||
Child = childB
|
{
|
||||||
}
|
TestPlan
|
||||||
},
|
.For(x => new SimpleStack
|
||||||
new Padding
|
{
|
||||||
{
|
First = x.CreateChild("first"),
|
||||||
Bottom = 100,
|
Second = x.CreateChild("second")
|
||||||
Child = new Container
|
})
|
||||||
{
|
.DrawElement(new Size(400, 300))
|
||||||
Child = childC
|
.ExpectChildMeasure("first", new Size(400, 300), new FullRender(200, 100))
|
||||||
}
|
.ExpectChildDraw("first", new Size(400, 100))
|
||||||
},
|
.ExpectChildMeasure("second", new Size(400, 200), new FullRender(250, 150))
|
||||||
}
|
.ExpectCanvasTranslate(0, 100)
|
||||||
}
|
.ExpectChildDraw("second", new Size(400, 150))
|
||||||
};
|
.ExpectCanvasTranslate(0, -100)
|
||||||
|
.CheckDrawResult();
|
||||||
structure.Child.Should().BeEquivalentTo(expected, o => o.WithStrictOrdering().IncludingAllRuntimeProperties());
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Draw_UsesEmpty_WhenFirstChildIsRendered()
|
||||||
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new SimpleStack
|
||||||
|
{
|
||||||
|
First = x.CreateChild("first"),
|
||||||
|
Second = x.CreateChild("second"),
|
||||||
|
|
||||||
|
IsFirstRendered = true
|
||||||
|
})
|
||||||
|
.DrawElement(new Size(400, 300))
|
||||||
|
.ExpectChildMeasure("second", new Size(400, 300), new PartialRender(200, 300))
|
||||||
|
.ExpectCanvasTranslate(0, 0)
|
||||||
|
.ExpectChildDraw("second", new Size(400, 300))
|
||||||
|
.ExpectCanvasTranslate(0, 0)
|
||||||
|
.CheckState<SimpleStack>(x => x.IsFirstRendered)
|
||||||
|
.CheckDrawResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Draw_TogglesFirstRenderedFlag_WhenSecondFullyRenders()
|
||||||
|
{
|
||||||
|
TestPlan
|
||||||
|
.For(x => new SimpleStack
|
||||||
|
{
|
||||||
|
First = x.CreateChild("first"),
|
||||||
|
Second = x.CreateChild("second"),
|
||||||
|
|
||||||
|
IsFirstRendered = true
|
||||||
|
})
|
||||||
|
.DrawElement(new Size(400, 300))
|
||||||
|
.ExpectChildMeasure("second", new Size(400, 300), new FullRender(200, 300))
|
||||||
|
.ExpectCanvasTranslate(0, 0)
|
||||||
|
.ExpectChildDraw("second", new Size(400, 300))
|
||||||
|
.ExpectCanvasTranslate(0, 0)
|
||||||
|
.CheckDrawResult()
|
||||||
|
.CheckState<SimpleStack>(x => !x.IsFirstRendered);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
// TODO: add tests for the spacing property
|
||||||
|
// TODO: add tests for the tree builder method
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,9 +49,9 @@ namespace QuestPDF.UnitTests.TestEngine
|
|||||||
TranslateFunc = position =>
|
TranslateFunc = position =>
|
||||||
{
|
{
|
||||||
var expected = GetExpected<CanvasTranslateOperationBase>();
|
var expected = GetExpected<CanvasTranslateOperationBase>();
|
||||||
|
|
||||||
Assert.AreEqual(expected.Position.X, position.X);
|
Assert.AreEqual(expected.Position.X, position.X, "Translate X");
|
||||||
Assert.AreEqual(expected.Position.Y, position.Y);
|
Assert.AreEqual(expected.Position.Y, position.Y, "Translate Y");
|
||||||
|
|
||||||
//position.Should().BeEquivalentTo(expected.Position);
|
//position.Should().BeEquivalentTo(expected.Position);
|
||||||
},
|
},
|
||||||
@@ -59,13 +59,13 @@ namespace QuestPDF.UnitTests.TestEngine
|
|||||||
{
|
{
|
||||||
var expected = GetExpected<CanvasDrawRectangleOperationBase>();
|
var expected = GetExpected<CanvasDrawRectangleOperationBase>();
|
||||||
|
|
||||||
Assert.AreEqual(expected.Position.X, position.X);
|
Assert.AreEqual(expected.Position.X, position.X, "Draw rectangle: X");
|
||||||
Assert.AreEqual(expected.Position.Y, position.Y);
|
Assert.AreEqual(expected.Position.Y, position.Y, "Draw rectangle: Y");
|
||||||
|
|
||||||
Assert.AreEqual(expected.Size.Width, size.Width);
|
Assert.AreEqual(expected.Size.Width, size.Width, "Draw rectangle: width");
|
||||||
Assert.AreEqual(expected.Size.Height, size.Height);
|
Assert.AreEqual(expected.Size.Height, size.Height, "Draw rectangle: height");
|
||||||
|
|
||||||
Assert.AreEqual(expected.Color, color);
|
Assert.AreEqual(expected.Color, color, "Draw rectangle: color");
|
||||||
|
|
||||||
/*position.Should().BeEquivalentTo(expected.Position);
|
/*position.Should().BeEquivalentTo(expected.Position);
|
||||||
size.Should().BeEquivalentTo(expected.Size);
|
size.Should().BeEquivalentTo(expected.Size);
|
||||||
@@ -77,12 +77,12 @@ namespace QuestPDF.UnitTests.TestEngine
|
|||||||
|
|
||||||
Assert.AreEqual(expected.Text, text);
|
Assert.AreEqual(expected.Text, text);
|
||||||
|
|
||||||
Assert.AreEqual(expected.Position.X, position.X);
|
Assert.AreEqual(expected.Position.X, position.X, "Draw text: X");
|
||||||
Assert.AreEqual(expected.Position.Y, position.Y);
|
Assert.AreEqual(expected.Position.Y, position.Y, "Draw text: Y");
|
||||||
|
|
||||||
Assert.AreEqual(expected.Style.Color, style.Color);
|
Assert.AreEqual(expected.Style.Color, style.Color, "Draw text: color");
|
||||||
Assert.AreEqual(expected.Style.FontType, style.FontType);
|
Assert.AreEqual(expected.Style.FontType, style.FontType, "Draw text: font");
|
||||||
Assert.AreEqual(expected.Style.Size, style.Size);
|
Assert.AreEqual(expected.Style.Size, style.Size, "Draw text: size");
|
||||||
|
|
||||||
/*text.Should().Be(expected.Text);
|
/*text.Should().Be(expected.Text);
|
||||||
position.Should().BeEquivalentTo(expected.Position);
|
position.Should().BeEquivalentTo(expected.Position);
|
||||||
@@ -92,11 +92,11 @@ namespace QuestPDF.UnitTests.TestEngine
|
|||||||
{
|
{
|
||||||
var expected = GetExpected<CanvasDrawImageOperationBase>();
|
var expected = GetExpected<CanvasDrawImageOperationBase>();
|
||||||
|
|
||||||
Assert.AreEqual(expected.Position.X, position.X);
|
Assert.AreEqual(expected.Position.X, position.X, "Draw image: X");
|
||||||
Assert.AreEqual(expected.Position.Y, position.Y);
|
Assert.AreEqual(expected.Position.Y, position.Y, "Draw image: Y");
|
||||||
|
|
||||||
Assert.AreEqual(expected.Size.Width, size.Width);
|
Assert.AreEqual(expected.Size.Width, size.Width, "Draw image: width");
|
||||||
Assert.AreEqual(expected.Size.Height, size.Height);
|
Assert.AreEqual(expected.Size.Height, size.Height, "Draw image: height");
|
||||||
|
|
||||||
/*position.Should().BeEquivalentTo(expected.Position);
|
/*position.Should().BeEquivalentTo(expected.Position);
|
||||||
size.Should().BeEquivalentTo(expected.Size);*/
|
size.Should().BeEquivalentTo(expected.Size);*/
|
||||||
@@ -117,8 +117,8 @@ namespace QuestPDF.UnitTests.TestEngine
|
|||||||
|
|
||||||
Assert.AreEqual(expected.ChildId, id);
|
Assert.AreEqual(expected.ChildId, id);
|
||||||
|
|
||||||
Assert.AreEqual(expected.Input.Width, availableSpace.Width);
|
Assert.AreEqual(expected.Input.Width, availableSpace.Width, $"Measure: width of child '{expected.ChildId}'");
|
||||||
Assert.AreEqual(expected.Input.Height, availableSpace.Height);
|
Assert.AreEqual(expected.Input.Height, availableSpace.Height, $"Measure: height of child '{expected.ChildId}'");
|
||||||
|
|
||||||
// id.Should().Be(expected.ChildId);
|
// id.Should().Be(expected.ChildId);
|
||||||
// availableSpace.Should().Be(expected.Input);
|
// availableSpace.Should().Be(expected.Input);
|
||||||
@@ -131,8 +131,8 @@ namespace QuestPDF.UnitTests.TestEngine
|
|||||||
|
|
||||||
Assert.AreEqual(expected.ChildId, id);
|
Assert.AreEqual(expected.ChildId, id);
|
||||||
|
|
||||||
Assert.AreEqual(expected.Input.Width, availableSpace.Width);
|
Assert.AreEqual(expected.Input.Width, availableSpace.Width, $"Draw: width of child '{expected.ChildId}'");
|
||||||
Assert.AreEqual(expected.Input.Height, availableSpace.Height);
|
Assert.AreEqual(expected.Input.Height, availableSpace.Height, $"Draw: width of child '{expected.ChildId}'");
|
||||||
|
|
||||||
/*id.Should().Be(expected.ChildId);
|
/*id.Should().Be(expected.ChildId);
|
||||||
availableSpace.Should().Be(expected.Input);*/
|
availableSpace.Should().Be(expected.Input);*/
|
||||||
@@ -214,8 +214,8 @@ namespace QuestPDF.UnitTests.TestEngine
|
|||||||
|
|
||||||
if (expectedSize != null)
|
if (expectedSize != null)
|
||||||
{
|
{
|
||||||
Assert.AreEqual(expectedSize.Width, actualSize.Width);
|
Assert.AreEqual(expectedSize.Width, actualSize.Width, "Measure: width");
|
||||||
Assert.AreEqual(expectedSize.Height, actualSize.Height);
|
Assert.AreEqual(expectedSize.Height, actualSize.Height, "Measure: height");
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -227,6 +227,19 @@ namespace QuestPDF.UnitTests.TestEngine
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TestPlan CheckState(Func<Element, bool> condition)
|
||||||
|
{
|
||||||
|
Assert.IsTrue(condition(Element), "Checking condition");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestPlan CheckState<T>(Func<T, bool> condition) where T : Element
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Element is T);
|
||||||
|
Assert.IsTrue(condition(Element as T), "Checking condition");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public static Element CreateUniqueElement()
|
public static Element CreateUniqueElement()
|
||||||
{
|
{
|
||||||
return new Text
|
return new Text
|
||||||
|
|||||||
@@ -1,13 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
using QuestPDF.Fluent;
|
using QuestPDF.Fluent;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
namespace QuestPDF.Elements
|
namespace QuestPDF.Elements
|
||||||
{
|
{
|
||||||
|
internal enum DecorationType
|
||||||
|
{
|
||||||
|
Prepend,
|
||||||
|
Append
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class SimpleDecoration : Element
|
||||||
|
{
|
||||||
|
public Element DecorationElement { get; set; } = Empty.Instance;
|
||||||
|
public Element ContentElement { get; set; } = Empty.Instance;
|
||||||
|
public DecorationType Type { get; set; }
|
||||||
|
|
||||||
|
internal override ISpacePlan Measure(Size availableSpace)
|
||||||
|
{
|
||||||
|
var decorationMeasure = DecorationElement?.Measure(availableSpace);
|
||||||
|
|
||||||
|
if (decorationMeasure is Wrap || decorationMeasure is PartialRender)
|
||||||
|
return new Wrap();
|
||||||
|
|
||||||
|
var decorationSize = decorationMeasure as Size ?? Size.Zero;
|
||||||
|
var contentMeasure = ContentElement?.Measure(new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height)) ?? new FullRender(Size.Zero);
|
||||||
|
|
||||||
|
if (contentMeasure is Wrap)
|
||||||
|
return new Wrap();
|
||||||
|
|
||||||
|
var contentSize = contentMeasure as Size ?? Size.Zero;
|
||||||
|
var resultSize = new Size(availableSpace.Width, decorationSize.Height + contentSize.Height);
|
||||||
|
|
||||||
|
if (contentSize is PartialRender)
|
||||||
|
return new PartialRender(resultSize);
|
||||||
|
|
||||||
|
if (contentSize is FullRender)
|
||||||
|
return new FullRender(resultSize);
|
||||||
|
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void Draw(ICanvas canvas, Size availableSpace)
|
||||||
|
{
|
||||||
|
var decorationSize = DecorationElement?.Measure(availableSpace) as Size ?? Size.Zero;
|
||||||
|
var contentSize = new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height);
|
||||||
|
|
||||||
|
var translateHeight = Type == DecorationType.Prepend ? decorationSize.Height : contentSize.Height;
|
||||||
|
Action drawDecoration = () => DecorationElement?.Draw(canvas, new Size(availableSpace.Width, decorationSize.Height));
|
||||||
|
Action drawContent = () => ContentElement?.Draw(canvas, 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
|
internal class Decoration : IComponent
|
||||||
{
|
{
|
||||||
public Element Header { get; set; } = new Empty();
|
public Element Header { get; set; } = Empty.Instance;
|
||||||
public Element Content { get; set; } = new Empty();
|
public Element Content { get; set; } = Empty.Instance;
|
||||||
public Element Footer { get; set; } = new Empty();
|
public Element Footer { get; set; } = Empty.Instance;
|
||||||
|
|
||||||
public void Compose(IContainer container)
|
public void Compose(IContainer container)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ namespace QuestPDF.Elements
|
|||||||
{
|
{
|
||||||
internal class Empty : Element
|
internal class Empty : Element
|
||||||
{
|
{
|
||||||
|
internal static Empty Instance { get; } = new Empty();
|
||||||
|
|
||||||
internal override ISpacePlan Measure(Size availableSpace)
|
internal override ISpacePlan Measure(Size availableSpace)
|
||||||
{
|
{
|
||||||
return new FullRender(Size.Zero);
|
return new FullRender(Size.Zero);
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ namespace QuestPDF.Elements
|
|||||||
{
|
{
|
||||||
internal class Page : IComponent
|
internal class Page : IComponent
|
||||||
{
|
{
|
||||||
public Element Header { get; set; } = new Empty();
|
public Element Header { get; set; } = Empty.Instance;
|
||||||
public Element Content { get; set; } = new Empty();
|
public Element Content { get; set; } = Empty.Instance;
|
||||||
public Element Footer { get; set; } = new Empty();
|
public Element Footer { get; set; } = Empty.Instance;
|
||||||
|
|
||||||
public void Compose(IContainer container)
|
public void Compose(IContainer container)
|
||||||
{
|
{
|
||||||
container.Decoration(section =>
|
container.Decoration(decoration =>
|
||||||
{
|
{
|
||||||
section.Header().Element(Header);
|
decoration.Header().Element(Header);
|
||||||
section.Content().Extend().Element(Content);
|
decoration.Content().Extend().Element(Content);
|
||||||
section.Footer().Element(Footer);
|
decoration.Footer().Element(Footer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-49
@@ -1,6 +1,8 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
namespace QuestPDF.Elements
|
namespace QuestPDF.Elements
|
||||||
@@ -31,78 +33,134 @@ namespace QuestPDF.Elements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class Row : Element
|
internal class SimpleRow : Element
|
||||||
{
|
{
|
||||||
public List<RowElement> Children { get; set; } = new List<RowElement>();
|
internal Element Left { get; set; }
|
||||||
|
internal Element Right { get; set; }
|
||||||
float? ConstantWidthSum { get; set; }
|
|
||||||
float? RelativeWidthSum { get; set; }
|
|
||||||
|
|
||||||
internal override ISpacePlan Measure(Size availableSpace)
|
internal override ISpacePlan Measure(Size availableSpace)
|
||||||
{
|
{
|
||||||
var sizes = Children
|
var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height)) as Size;
|
||||||
.Select(x =>
|
|
||||||
{
|
|
||||||
var space = GetTargetSize(x, availableSpace);
|
|
||||||
return x.Child.Measure(space);
|
|
||||||
})
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (sizes.Any(x => x is Wrap))
|
if (leftMeasurement == null)
|
||||||
return new Wrap();
|
return new Wrap();
|
||||||
|
|
||||||
var height = sizes
|
|
||||||
.Where(x => x is Size)
|
|
||||||
.Cast<Size>()
|
|
||||||
.DefaultIfEmpty(Size.Zero)
|
|
||||||
.Max(x => x.Height);
|
|
||||||
|
|
||||||
if (sizes.All(x => x is FullRender))
|
var rightMeasurement = Right.Measure(new Size(availableSpace.Width - leftMeasurement.Width, availableSpace.Height)) as Size;
|
||||||
return new FullRender(availableSpace.Width, height);
|
|
||||||
|
|
||||||
if (sizes.Any(x => x is PartialRender))
|
|
||||||
return new PartialRender(availableSpace.Width, height);
|
|
||||||
|
|
||||||
return new FullRender(Size.Zero);
|
if (rightMeasurement == null)
|
||||||
|
return new Wrap();
|
||||||
|
|
||||||
|
var totalWidth = leftMeasurement.Width + rightMeasurement.Width;
|
||||||
|
var totalHeight = Math.Max(leftMeasurement.Height, rightMeasurement.Height);
|
||||||
|
|
||||||
|
var targetSize = new Size(totalWidth, totalHeight);
|
||||||
|
|
||||||
|
if (leftMeasurement is PartialRender || rightMeasurement is PartialRender)
|
||||||
|
return new PartialRender(targetSize);
|
||||||
|
|
||||||
|
return new FullRender(targetSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Draw(ICanvas canvas, Size availableSpace)
|
internal override void Draw(ICanvas canvas, Size availableSpace)
|
||||||
{
|
{
|
||||||
var targetSpace = Measure(availableSpace) as Size;
|
var leftMeasurement = Left.Measure(new Size(availableSpace.Width, availableSpace.Height));
|
||||||
|
var leftWidth = (leftMeasurement as Size)?.Width ?? 0;
|
||||||
if (targetSpace == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var offset = 0f;
|
Left.Draw(canvas, new Size(leftWidth, availableSpace.Height));
|
||||||
|
|
||||||
foreach (var column in Children)
|
canvas.Translate(new Position(leftWidth, 0));
|
||||||
{
|
Right.Draw(canvas, new Size(availableSpace.Width - leftWidth, availableSpace.Height));
|
||||||
var space = GetTargetSize(column, targetSpace);
|
canvas.Translate(new Position(-leftWidth, 0));
|
||||||
|
}
|
||||||
canvas.Translate(new Position(offset, 0));
|
}
|
||||||
column.Child.Draw(canvas, space);
|
|
||||||
canvas.Translate(new Position(-offset, 0));
|
internal class Row : Element
|
||||||
|
{
|
||||||
offset += space.Width;
|
public ICollection<RowElement> Children { get; internal set; } = new List<RowElement>();
|
||||||
}
|
public float Spacing { get; set; } = 0;
|
||||||
|
|
||||||
|
internal override ISpacePlan Measure(Size availableSpace)
|
||||||
|
{
|
||||||
|
return Compose(availableSpace.Width).Measure(availableSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Size GetTargetSize(RowElement rowElement, Size availableSpace)
|
internal override void Draw(ICanvas canvas, Size availableSpace)
|
||||||
{
|
{
|
||||||
if (rowElement is ConstantRowElement)
|
Compose(availableSpace.Width).Draw(canvas, availableSpace);
|
||||||
return new Size(rowElement.Width, availableSpace.Height);
|
}
|
||||||
|
|
||||||
ConstantWidthSum ??= Children
|
#region structure
|
||||||
|
|
||||||
|
private Element Compose(float availableWidth)
|
||||||
|
{
|
||||||
|
var elements = AddSpacing(Children, Spacing);
|
||||||
|
var rowElements = ReduceRows(elements, availableWidth);
|
||||||
|
return BuildTree(rowElements.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ICollection<Element> ReduceRows(ICollection<RowElement> elements, float availableWidth)
|
||||||
|
{
|
||||||
|
var constantWidth = elements
|
||||||
.Where(x => x is ConstantRowElement)
|
.Where(x => x is ConstantRowElement)
|
||||||
.Cast<ConstantRowElement>()
|
.Cast<ConstantRowElement>()
|
||||||
.Sum(x => x.Width);
|
.Sum(x => x.Width);
|
||||||
|
|
||||||
RelativeWidthSum ??= Children
|
var relativeWidth = elements
|
||||||
.Where(x => x is RelativeRowElement)
|
.Where(x => x is RelativeRowElement)
|
||||||
.Cast<RelativeRowElement>()
|
.Cast<RelativeRowElement>()
|
||||||
.Sum(x => x.Width);
|
.Sum(x => x.Width);
|
||||||
|
|
||||||
|
var widthPerRelativeUnit = (availableWidth - constantWidth) / relativeWidth;
|
||||||
|
|
||||||
return new Size((availableSpace.Width - ConstantWidthSum.Value) * rowElement.Width / RelativeWidthSum.Value, availableSpace.Height);
|
return elements
|
||||||
|
.Select(x =>
|
||||||
|
{
|
||||||
|
if (x is RelativeRowElement r)
|
||||||
|
return new ConstantRowElement(r.Width * widthPerRelativeUnit)
|
||||||
|
{
|
||||||
|
Child = x.Child
|
||||||
|
};
|
||||||
|
|
||||||
|
return x;
|
||||||
|
})
|
||||||
|
.Select(x => new Constrained
|
||||||
|
{
|
||||||
|
MinWidth = x.Width,
|
||||||
|
MaxWidth = x.Width,
|
||||||
|
Child = x.Child
|
||||||
|
})
|
||||||
|
.Cast<Element>()
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ICollection<RowElement> AddSpacing(ICollection<RowElement> elements, float spacing)
|
||||||
|
{
|
||||||
|
if (spacing < Size.Epsilon)
|
||||||
|
return elements;
|
||||||
|
|
||||||
|
return elements
|
||||||
|
.SelectMany(x => new[] { new ConstantRowElement(spacing), 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 SimpleRow
|
||||||
|
{
|
||||||
|
Left = BuildTree(elements.Slice(0, half)),
|
||||||
|
Right = BuildTree(elements.Slice(half))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
using System;
|
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
|
||||||
using QuestPDF.Infrastructure;
|
|
||||||
|
|
||||||
namespace QuestPDF.Elements
|
|
||||||
{
|
|
||||||
internal enum DecorationType
|
|
||||||
{
|
|
||||||
Prepend,
|
|
||||||
Append
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class SimpleDecoration : Element
|
|
||||||
{
|
|
||||||
public Element DecorationElement { get; set; } = new Empty();
|
|
||||||
public Element ContentElement { get; set; } = new Empty();
|
|
||||||
public DecorationType Type { get; set; }
|
|
||||||
|
|
||||||
internal override ISpacePlan Measure(Size availableSpace)
|
|
||||||
{
|
|
||||||
var decorationMeasure = DecorationElement?.Measure(availableSpace);
|
|
||||||
|
|
||||||
if (decorationMeasure is Wrap || decorationMeasure is PartialRender)
|
|
||||||
return new Wrap();
|
|
||||||
|
|
||||||
var decorationSize = decorationMeasure as Size ?? Size.Zero;
|
|
||||||
var contentMeasure = ContentElement?.Measure(new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height)) ?? new FullRender(Size.Zero);
|
|
||||||
|
|
||||||
if (contentMeasure is Wrap)
|
|
||||||
return new Wrap();
|
|
||||||
|
|
||||||
var contentSize = contentMeasure as Size ?? Size.Zero;
|
|
||||||
var resultSize = new Size(availableSpace.Width, decorationSize.Height + contentSize.Height);
|
|
||||||
|
|
||||||
if (contentSize is PartialRender)
|
|
||||||
return new PartialRender(resultSize);
|
|
||||||
|
|
||||||
if (contentSize is FullRender)
|
|
||||||
return new FullRender(resultSize);
|
|
||||||
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void Draw(ICanvas canvas, Size availableSpace)
|
|
||||||
{
|
|
||||||
var decorationSize = DecorationElement?.Measure(availableSpace) as Size ?? Size.Zero;
|
|
||||||
var contentSize = new Size(availableSpace.Width, availableSpace.Height - decorationSize.Height);
|
|
||||||
|
|
||||||
var translateHeight = Type == DecorationType.Prepend ? decorationSize.Height : contentSize.Height;
|
|
||||||
Action drawDecoration = () => DecorationElement?.Draw(canvas, new Size(availableSpace.Width, decorationSize.Height));
|
|
||||||
Action drawContent = () => ContentElement?.Draw(canvas, 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+101
-56
@@ -1,81 +1,126 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using QuestPDF.Drawing.SpacePlan;
|
using QuestPDF.Drawing.SpacePlan;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
using QuestPDF.Infrastructure;
|
using QuestPDF.Infrastructure;
|
||||||
|
using IComponent = QuestPDF.Infrastructure.IComponent;
|
||||||
|
using IContainer = QuestPDF.Infrastructure.IContainer;
|
||||||
|
|
||||||
namespace QuestPDF.Elements
|
namespace QuestPDF.Elements
|
||||||
{
|
{
|
||||||
internal class Stack : Element
|
internal class SimpleStack : Element
|
||||||
{
|
{
|
||||||
public ICollection<Element?> Children { get; internal set; } = new List<Element?>();
|
internal Element First { get; set; } = Empty.Instance;
|
||||||
private Queue<Element?> ChildrenQueue { get; set; } = new Queue<Element?>();
|
internal Element Second { get; set; } = Empty.Instance;
|
||||||
|
|
||||||
private void Initialize()
|
internal bool IsFirstRendered { get; set; } = false;
|
||||||
{
|
|
||||||
if (ChildrenQueue.Count == 0)
|
|
||||||
ChildrenQueue = new Queue<Element>(Children.Where(x => x != null));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override ISpacePlan Measure(Size availableSpace)
|
internal override ISpacePlan Measure(Size availableSpace)
|
||||||
{
|
{
|
||||||
Initialize();
|
var firstElement = IsFirstRendered ? Empty.Instance : First;
|
||||||
|
var firstSize = firstElement.Measure(availableSpace) as Size;
|
||||||
|
|
||||||
|
if (firstSize == null)
|
||||||
|
return new Wrap();
|
||||||
|
|
||||||
if(!ChildrenQueue.Any())
|
if (firstSize is PartialRender partialRender)
|
||||||
return new FullRender(Size.Zero);
|
return partialRender;
|
||||||
|
|
||||||
|
var spaceForSecond = new Size(availableSpace.Width, availableSpace.Height - firstSize.Height);
|
||||||
|
var secondSize = Second.Measure(spaceForSecond) as Size;
|
||||||
|
|
||||||
var heightOnCurrentPage = 0f;
|
if (secondSize == null)
|
||||||
|
return new PartialRender(firstSize);
|
||||||
|
|
||||||
foreach (var renderer in ChildrenQueue)
|
var totalWidth = Math.Max(firstSize.Width, secondSize.Width);
|
||||||
{
|
var totalHeight = firstSize.Height + secondSize.Height;
|
||||||
var space = renderer.Measure(new Size(availableSpace.Width, availableSpace.Height - heightOnCurrentPage));
|
var targetSize = new Size(totalWidth, totalHeight);
|
||||||
|
|
||||||
if (space is Wrap)
|
if (secondSize is PartialRender)
|
||||||
{
|
return new PartialRender(targetSize);
|
||||||
if (heightOnCurrentPage < Size.Epsilon)
|
|
||||||
return new Wrap();
|
return new FullRender(targetSize);
|
||||||
|
|
||||||
return new PartialRender(availableSpace.Width, heightOnCurrentPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
var size = space as Size;
|
|
||||||
heightOnCurrentPage += size.Height;
|
|
||||||
|
|
||||||
if (space is PartialRender)
|
|
||||||
return new PartialRender(availableSpace.Width, heightOnCurrentPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new FullRender(availableSpace.Width, heightOnCurrentPage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void Draw(ICanvas canvas, Size availableSpace)
|
internal override void Draw(ICanvas canvas, Size availableSpace)
|
||||||
{
|
{
|
||||||
Initialize();
|
var firstElement = IsFirstRendered ? Empty.Instance : First;
|
||||||
|
|
||||||
|
var firstMeasurement = firstElement.Measure(availableSpace);
|
||||||
|
|
||||||
|
if (firstMeasurement is FullRender)
|
||||||
|
IsFirstRendered = true;
|
||||||
|
|
||||||
|
var firstSize = firstMeasurement as Size;
|
||||||
|
|
||||||
|
if (firstSize != null)
|
||||||
|
firstElement.Draw(canvas, new Size(availableSpace.Width, firstSize.Height));
|
||||||
|
|
||||||
|
if (firstMeasurement is Wrap || firstMeasurement is PartialRender)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var firstHeight = firstSize?.Height ?? 0;
|
||||||
|
var spaceForSecond = new Size(availableSpace.Width, availableSpace.Height - firstHeight);
|
||||||
|
var secondMeasurement = Second?.Measure(spaceForSecond) as Size;
|
||||||
|
|
||||||
|
if (secondMeasurement == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
canvas.Translate(new Position(0, firstHeight));
|
||||||
|
Second.Draw(canvas, new Size(availableSpace.Width, secondMeasurement.Height));
|
||||||
|
canvas.Translate(new Position(0, -firstHeight));
|
||||||
|
|
||||||
var topOffset = 0f;
|
if (secondMeasurement is FullRender)
|
||||||
|
IsFirstRendered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class Stack : IComponent
|
||||||
|
{
|
||||||
|
public ICollection<Element> Children { get; internal set; } = new List<Element>();
|
||||||
|
public float Spacing { get; set; } = 0;
|
||||||
|
|
||||||
|
public void Compose(IContainer container)
|
||||||
|
{
|
||||||
|
var elements = AddSpacing(Spacing, Children);
|
||||||
|
|
||||||
while (ChildrenQueue.Any())
|
container
|
||||||
|
.PaddingBottom(-Spacing)
|
||||||
|
.Element(BuildTree(elements.ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ICollection<Element> AddSpacing(float spacing, ICollection<Element> elements)
|
||||||
|
{
|
||||||
|
if (spacing < Size.Epsilon)
|
||||||
|
return elements;
|
||||||
|
|
||||||
|
return elements
|
||||||
|
.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 SimpleStack
|
||||||
{
|
{
|
||||||
var child = ChildrenQueue.Peek();
|
First = BuildTree(elements.Slice(0, half)),
|
||||||
|
Second = BuildTree(elements.Slice(half))
|
||||||
var restSpace = new Size(availableSpace.Width, availableSpace.Height - topOffset);
|
};
|
||||||
var space = child.Measure(restSpace);
|
|
||||||
|
|
||||||
if (space is Wrap)
|
|
||||||
break;
|
|
||||||
|
|
||||||
var size = space as Size;
|
|
||||||
|
|
||||||
canvas.Translate(new Position(0, topOffset));
|
|
||||||
child.Draw(canvas, new Size(availableSpace.Width, size.Height));
|
|
||||||
canvas.Translate(new Position(0, -topOffset));
|
|
||||||
|
|
||||||
topOffset += size.Height;
|
|
||||||
|
|
||||||
if (space is PartialRender)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ChildrenQueue.Dequeue();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ namespace QuestPDF.Fluent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SectionExtensions
|
public static class DecorationExtensions
|
||||||
{
|
{
|
||||||
public static void Decoration(this IContainer element, Action<DecorationDescriptor> handler)
|
public static void Decoration(this IContainer element, Action<DecorationDescriptor> handler)
|
||||||
{
|
{
|
||||||
@@ -163,4 +163,4 @@ namespace QuestPDF.Fluent
|
|||||||
return element.Element(new Box());
|
return element.Element(new Box());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ namespace QuestPDF.Fluent
|
|||||||
public void AlignCenter() => Alignment(HorizontalAlignment.Center);
|
public void AlignCenter() => Alignment(HorizontalAlignment.Center);
|
||||||
public void AlignRight() => Alignment(HorizontalAlignment.Right);
|
public void AlignRight() => Alignment(HorizontalAlignment.Right);
|
||||||
|
|
||||||
public IContainer Element(int columns = 1)
|
public IContainer Item(int columns = 1)
|
||||||
{
|
{
|
||||||
var container = new Container();
|
var container = new Container();
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,6 @@ namespace QuestPDF.Fluent
|
|||||||
Page.Header = container;
|
Page.Header = container;
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Header(Action<IContainer> handler)
|
|
||||||
{
|
|
||||||
handler?.Invoke(Header());
|
|
||||||
}
|
|
||||||
|
|
||||||
public IContainer Content()
|
public IContainer Content()
|
||||||
{
|
{
|
||||||
@@ -27,22 +22,12 @@ namespace QuestPDF.Fluent
|
|||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Content(Action<IContainer> handler)
|
|
||||||
{
|
|
||||||
handler?.Invoke(Content());
|
|
||||||
}
|
|
||||||
|
|
||||||
public IContainer Footer()
|
public IContainer Footer()
|
||||||
{
|
{
|
||||||
var container = new Container();
|
var container = new Container();
|
||||||
Page.Footer = container;
|
Page.Footer = container;
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Footer(Action<IContainer> handler)
|
|
||||||
{
|
|
||||||
handler?.Invoke(Footer());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PageExtensions
|
public static class PageExtensions
|
||||||
|
|||||||
@@ -8,19 +8,18 @@ namespace QuestPDF.Fluent
|
|||||||
{
|
{
|
||||||
public class RowDescriptor
|
public class RowDescriptor
|
||||||
{
|
{
|
||||||
private List<RowElement> Elements { get; } = new List<RowElement>();
|
internal Row Row { get; } = new Row();
|
||||||
private float RowSpacing { get; set; } = 0;
|
|
||||||
|
|
||||||
public void Spacing(float value)
|
public void Spacing(float value)
|
||||||
{
|
{
|
||||||
RowSpacing = value;
|
Row.Spacing = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IContainer ConstantColumn(float width)
|
public IContainer ConstantColumn(float width)
|
||||||
{
|
{
|
||||||
var element = new ConstantRowElement(width);
|
var element = new ConstantRowElement(width);
|
||||||
|
|
||||||
Elements.Add(element);
|
Row.Children.Add(element);
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,36 +27,9 @@ namespace QuestPDF.Fluent
|
|||||||
{
|
{
|
||||||
var element = new RelativeRowElement(width);
|
var element = new RelativeRowElement(width);
|
||||||
|
|
||||||
Elements.Add(element);
|
Row.Children.Add(element);
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Element CreateRow()
|
|
||||||
{
|
|
||||||
if (Elements.Count == 0)
|
|
||||||
return new Empty();
|
|
||||||
|
|
||||||
if (RowSpacing <= Size.Epsilon)
|
|
||||||
return new Row
|
|
||||||
{
|
|
||||||
Children = Elements
|
|
||||||
};
|
|
||||||
|
|
||||||
var children = Elements
|
|
||||||
.SelectMany(x => new[] {x, new ConstantRowElement(RowSpacing) })
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var row = new Row
|
|
||||||
{
|
|
||||||
Children = children
|
|
||||||
};
|
|
||||||
|
|
||||||
return new Padding
|
|
||||||
{
|
|
||||||
Right = -RowSpacing,
|
|
||||||
Child = row
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RowExtensions
|
public static class RowExtensions
|
||||||
@@ -66,7 +38,7 @@ namespace QuestPDF.Fluent
|
|||||||
{
|
{
|
||||||
var descriptor = new RowDescriptor();
|
var descriptor = new RowDescriptor();
|
||||||
handler(descriptor);
|
handler(descriptor);
|
||||||
element.Element(descriptor.CreateRow());
|
element.Element(descriptor.Row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,57 +8,19 @@ namespace QuestPDF.Fluent
|
|||||||
{
|
{
|
||||||
public class StackDescriptor
|
public class StackDescriptor
|
||||||
{
|
{
|
||||||
private List<Element> Items { get; } = new List<Element>();
|
internal Stack Stack { get; } = new Stack();
|
||||||
private float StackSpacing { get; set; } = 0;
|
|
||||||
|
|
||||||
public void Spacing(float value)
|
public void Spacing(float value)
|
||||||
{
|
{
|
||||||
StackSpacing = value;
|
Stack.Spacing = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IContainer Item()
|
public IContainer Item()
|
||||||
{
|
{
|
||||||
var container = new Container();
|
var container = new Container();
|
||||||
Items.Add(container);
|
Stack.Children.Add(container);
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Item(Action<IContainer> handler)
|
|
||||||
{
|
|
||||||
handler?.Invoke(Item());
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Element CreateStack()
|
|
||||||
{
|
|
||||||
if (Items.Count == 0)
|
|
||||||
return new Empty();
|
|
||||||
|
|
||||||
if (StackSpacing <= Size.Epsilon)
|
|
||||||
return new Stack
|
|
||||||
{
|
|
||||||
Children = Items
|
|
||||||
};
|
|
||||||
|
|
||||||
var children = Items
|
|
||||||
.Select(x => new Padding
|
|
||||||
{
|
|
||||||
Bottom = StackSpacing,
|
|
||||||
Child = x
|
|
||||||
})
|
|
||||||
.Cast<Element>()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var stack = new Stack
|
|
||||||
{
|
|
||||||
Children = children
|
|
||||||
};
|
|
||||||
|
|
||||||
return new Padding
|
|
||||||
{
|
|
||||||
Bottom = -StackSpacing,
|
|
||||||
Child = stack
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StackExtensions
|
public static class StackExtensions
|
||||||
@@ -67,7 +29,7 @@ namespace QuestPDF.Fluent
|
|||||||
{
|
{
|
||||||
var descriptor = new StackDescriptor();
|
var descriptor = new StackDescriptor();
|
||||||
handler(descriptor);
|
handler(descriptor);
|
||||||
element.Element(descriptor.CreateStack());
|
element.Component(descriptor.Stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ namespace QuestPDF.Infrastructure
|
|||||||
{
|
{
|
||||||
internal abstract class ContainerElement : Element, IContainer
|
internal abstract class ContainerElement : Element, IContainer
|
||||||
{
|
{
|
||||||
internal Element? Child { get; set; } = new Empty();
|
internal Element? Child { get; set; } = Empty.Instance;
|
||||||
|
|
||||||
IElement? IContainer.Child
|
IElement? IContainer.Child
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user