From 5ff9d03f2074aa068ddfe35eb8df79440c837366 Mon Sep 17 00:00:00 2001 From: MarcinZiabek Date: Thu, 29 Sep 2022 14:14:00 +0200 Subject: [PATCH] Prototype for the RTL mode --- QuestPDF.Examples/RightToLeftExamples.cs | 55 +++++++++++++++++++ QuestPDF/Drawing/DocumentGenerator.cs | 19 +++++++ QuestPDF/Elements/ContentDirectionSetter.cs | 9 +++ QuestPDF/Elements/Row.cs | 9 ++- QuestPDF/Elements/Unconstrained.cs | 10 +++- QuestPDF/Fluent/ContentDirectionExtensions.cs | 26 +++++++++ QuestPDF/Infrastructure/ContentDirection.cs | 8 +++ .../Infrastructure/IContentDirectionAware.cs | 7 +++ 8 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 QuestPDF.Examples/RightToLeftExamples.cs create mode 100644 QuestPDF/Elements/ContentDirectionSetter.cs create mode 100644 QuestPDF/Fluent/ContentDirectionExtensions.cs create mode 100644 QuestPDF/Infrastructure/ContentDirection.cs create mode 100644 QuestPDF/Infrastructure/IContentDirectionAware.cs diff --git a/QuestPDF.Examples/RightToLeftExamples.cs b/QuestPDF.Examples/RightToLeftExamples.cs new file mode 100644 index 0000000..aa26e0e --- /dev/null +++ b/QuestPDF.Examples/RightToLeftExamples.cs @@ -0,0 +1,55 @@ +using NUnit.Framework; +using QuestPDF.Examples.Engine; +using QuestPDF.Fluent; +using QuestPDF.Helpers; + +namespace QuestPDF.Examples +{ + public class RightToLeftExamples + { + [Test] + public void Unconstrained() + { + RenderingTest + .Create() + .ProduceImages() + .PageSize(600, 600) + .ShowResults() + .Render(container => + { + container + .AlignCenter() + .AlignMiddle() + .ContentFromRightToLeft() + .Unconstrained() + .Background(Colors.Red.Medium) + .Height(200) + .Width(200); + }); + } + + [Test] + public void Row() + { + RenderingTest + .Create() + .ProduceImages() + .PageSize(600, 600) + .ShowResults() + .Render(container => + { + container + .Padding(25) + .ContentFromRightToLeft() + .Border(1) + .MinimalBox() + .Row(row => + { + row.ConstantItem(200).Background(Colors.Red.Lighten2).Height(200); + row.ConstantItem(150).Background(Colors.Green.Lighten2).Height(200); + row.ConstantItem(100).Background(Colors.Blue.Lighten2).Height(200); + }); + }); + } + } +} \ No newline at end of file diff --git a/QuestPDF/Drawing/DocumentGenerator.cs b/QuestPDF/Drawing/DocumentGenerator.cs index b64baac..eb9a9ab 100644 --- a/QuestPDF/Drawing/DocumentGenerator.cs +++ b/QuestPDF/Drawing/DocumentGenerator.cs @@ -65,6 +65,7 @@ namespace QuestPDF.Drawing document.Compose(container); var content = container.Compose(); ApplyDefaultTextStyle(content, TextStyle.LibraryDefault); + ApplyContentDirection(content, ContentDirection.LeftToRight); var debuggingState = Settings.EnableDebugging ? ApplyDebugging(content) : null; @@ -160,6 +161,24 @@ namespace QuestPDF.Drawing return debuggingState; } + + private static void ApplyContentDirection(Element? content, ContentDirection direction) + { + if (content == null) + return; + + if (content is ContentDirectionSetter contentDirectionSetter) + { + ApplyContentDirection(contentDirectionSetter.Child, contentDirectionSetter.ContentDirection); + return; + } + + if (content is IContentDirectionAware contentDirectionAware) + contentDirectionAware.ContentDirection = direction; + + foreach (var child in content.GetChildren()) + ApplyContentDirection(child, direction); + } internal static void ApplyDefaultTextStyle(this Element? content, TextStyle documentDefaultTextStyle) { diff --git a/QuestPDF/Elements/ContentDirectionSetter.cs b/QuestPDF/Elements/ContentDirectionSetter.cs new file mode 100644 index 0000000..a5182b4 --- /dev/null +++ b/QuestPDF/Elements/ContentDirectionSetter.cs @@ -0,0 +1,9 @@ +using QuestPDF.Infrastructure; + +namespace QuestPDF.Elements +{ + internal class ContentDirectionSetter : ContainerElement + { + public ContentDirection ContentDirection { get; set; } + } +} \ No newline at end of file diff --git a/QuestPDF/Elements/Row.cs b/QuestPDF/Elements/Row.cs index cdf6a63..1682d93 100644 --- a/QuestPDF/Elements/Row.cs +++ b/QuestPDF/Elements/Row.cs @@ -31,8 +31,10 @@ namespace QuestPDF.Elements public Position Offset { get; set; } } - internal class Row : Element, ICacheable, IStateResettable + internal class Row : Element, ICacheable, IStateResettable, IContentDirectionAware { + public ContentDirection ContentDirection { get; set; } + internal List Items { get; } = new(); internal float Spacing { get; set; } @@ -62,7 +64,7 @@ namespace QuestPDF.Elements if (renderingCommands.Any(x => !x.RowItem.IsRendered && x.Measurement.Type == SpacePlanType.Wrap)) return SpacePlan.Wrap(); - var width = renderingCommands.Last().Offset.X + renderingCommands.Last().Size.Width; + var width = renderingCommands.Max(c => c.Offset.X + c.Size.Width); var height = renderingCommands.Max(x => x.Size.Height); var size = new Size(width, height); @@ -152,6 +154,9 @@ namespace QuestPDF.Elements { command.Size = new Size(command.Size.Width, rowHeight); command.Measurement = command.RowItem.Measure(command.Size); + + if (ContentDirection == ContentDirection.RightToLeft) + command.Offset = new Position(availableSpace.Width - command.Offset.X - command.Size.Width, 0); } return renderingCommands; diff --git a/QuestPDF/Elements/Unconstrained.cs b/QuestPDF/Elements/Unconstrained.cs index a3834b3..4badbd3 100644 --- a/QuestPDF/Elements/Unconstrained.cs +++ b/QuestPDF/Elements/Unconstrained.cs @@ -3,8 +3,10 @@ using QuestPDF.Infrastructure; namespace QuestPDF.Elements { - internal class Unconstrained : ContainerElement, ICacheable + internal class Unconstrained : ContainerElement, IContentDirectionAware, ICacheable { + public ContentDirection ContentDirection { get; set; } + internal override SpacePlan Measure(Size availableSpace) { var childSize = base.Measure(Size.Max); @@ -25,7 +27,13 @@ namespace QuestPDF.Elements if (measurement.Type == SpacePlanType.Wrap) return; + var translate = ContentDirection == ContentDirection.RightToLeft + ? new Position(-measurement.Width, 0) + : Position.Zero; + + Canvas.Translate(translate); base.Draw(measurement); + Canvas.Translate(translate.Reverse()); } } } \ No newline at end of file diff --git a/QuestPDF/Fluent/ContentDirectionExtensions.cs b/QuestPDF/Fluent/ContentDirectionExtensions.cs new file mode 100644 index 0000000..82bd734 --- /dev/null +++ b/QuestPDF/Fluent/ContentDirectionExtensions.cs @@ -0,0 +1,26 @@ +using QuestPDF.Elements; +using QuestPDF.Infrastructure; + +namespace QuestPDF.Fluent +{ + public static class ContentDirectionExtensions + { + private static IContainer ContentDirection(this IContainer element, ContentDirection direction) + { + return element.Element(new ContentDirectionSetter() + { + ContentDirection = direction + }); + } + + public static IContainer ContentFromLeftToRight(this IContainer element) + { + return element.ContentDirection(Infrastructure.ContentDirection.LeftToRight); + } + + public static IContainer ContentFromRightToLeft(this IContainer element) + { + return element.ContentDirection(Infrastructure.ContentDirection.RightToLeft); + } + } +} \ No newline at end of file diff --git a/QuestPDF/Infrastructure/ContentDirection.cs b/QuestPDF/Infrastructure/ContentDirection.cs new file mode 100644 index 0000000..81a17f2 --- /dev/null +++ b/QuestPDF/Infrastructure/ContentDirection.cs @@ -0,0 +1,8 @@ +namespace QuestPDF.Infrastructure +{ + internal enum ContentDirection + { + LeftToRight, + RightToLeft + } +} \ No newline at end of file diff --git a/QuestPDF/Infrastructure/IContentDirectionAware.cs b/QuestPDF/Infrastructure/IContentDirectionAware.cs new file mode 100644 index 0000000..eb68d4e --- /dev/null +++ b/QuestPDF/Infrastructure/IContentDirectionAware.cs @@ -0,0 +1,7 @@ +namespace QuestPDF.Infrastructure +{ + internal interface IContentDirectionAware + { + public ContentDirection ContentDirection { get; set; } + } +} \ No newline at end of file