Browse Source

Text component: internal and external links

Marcin Ziąbek 4 years ago
parent
commit
b66a53a189

+ 29 - 6
QuestPDF.Examples/TextBenchmark.cs

@@ -127,6 +127,8 @@ namespace QuestPDF.Examples
                                 stack.Item().PageBreak();
 
                                 Chapters(stack);
+
+                                stack.Item().Element(Summary);
                             });
 
                         decoration.Footer().Element(Footer);
@@ -141,8 +143,8 @@ namespace QuestPDF.Examples
                     .AlignBottom()
                     .Stack(stack =>
                     {
-                        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));
+                        stack.Item().Debug().Text("Quo Vadis", TextStyle.Default.Size(72).Bold().Color(Colors.Blue.Darken2));
+                        stack.Item().Debug().Text("Henryk Sienkiewicz", TextStyle.Default.Size(24).Color(Colors.Grey.Darken2));
                     });
             }
 
@@ -150,8 +152,7 @@ namespace QuestPDF.Examples
             {
                 container.Stack(stack =>
                 {
-                    stack.Item().Text("Table of contents", subtitleStyle);
-                    stack.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal();
+                    SectionTitle(stack, "Table of contents");
                     
                     foreach (var chapter in chapters)
                     {
@@ -176,8 +177,7 @@ namespace QuestPDF.Examples
             {
                 container.Stack(stack =>
                 {
-                    stack.Item().Location(title).Text(title, subtitleStyle);
-                    stack.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal();
+                    SectionTitle(stack, title);
   
                     stack.Item().Text(text =>
                     {
@@ -189,6 +189,29 @@ namespace QuestPDF.Examples
                 });
             }
 
+            void Summary(IContainer container)
+            {
+                container.Stack(stack =>
+                {
+                    SectionTitle(stack, "Acknowledgements");
+                    
+                    stack.Item().Text(text =>
+                    {
+                        text.DefaultTextStyle(normalStyle);
+                        
+                        text.Span("This document was generated based on the book available on the ");
+                        text.ExternalLocation("wolnelektury.pl", "https://wolnelektury.pl/", normalStyle.Color(Colors.Blue.Medium).Underlined());
+                        text.Span(" website. Thank you!");
+                    });
+                });
+            }
+
+            void SectionTitle(StackDescriptor stack, string text)
+            {
+                stack.Item().Location(text).Text(text, subtitleStyle);
+                stack.Item().PaddingTop(10).PaddingBottom(50).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).ExtendHorizontal();
+            }
+            
             void Footer(IContainer container)
             {
                 container

+ 1 - 1
QuestPDF/Elements/Text/TextBlock.cs

@@ -148,7 +148,7 @@ namespace QuestPDF.Elements.Text
                 if (!line.Elements.Any())
                     yield break;
                 
-                if (currentHeight + line.LineHeight > availableHeight)
+                if (currentHeight + line.LineHeight > availableHeight + Size.Epsilon)
                     yield break;
 
                 currentHeight += line.LineHeight;

+ 60 - 0
QuestPDF/Elements/Text/TextItem.cs

@@ -165,4 +165,64 @@ namespace QuestPDF.Elements.Text
             };
         }
     }
+
+    internal class InternalLinkTextItem : ITextElement
+    {
+        public TextStyle Style { get; set; } = new TextStyle();
+        public string Text { get; set; }
+        public string LocationName { get; set; }
+        
+        public TextMeasurementResult? Measure(TextMeasurementRequest request)
+        {
+            return GetItem().MeasureWithoutCache(request);
+        }
+
+        public void Draw(TextDrawingRequest request)
+        {
+            request.Canvas.Translate(new Position(0, request.TotalAscent));
+            request.Canvas.DrawLocationLink(LocationName, new Size(request.TextSize.Width, request.TextSize.Height));
+            request.Canvas.Translate(new Position(0, -request.TotalAscent));
+            
+            GetItem().Draw(request);
+        }
+
+        private TextItem GetItem()
+        {
+            return new TextItem
+            {
+                Style = Style,
+                Text = Text
+            };
+        }
+    }
+    
+    internal class ExternalLinkTextItem : ITextElement
+    {
+        public TextStyle Style { get; set; } = new TextStyle();
+        public string Text { get; set; }
+        public string Url { get; set; }
+        
+        public TextMeasurementResult? Measure(TextMeasurementRequest request)
+        {
+            return GetItem().MeasureWithoutCache(request);
+        }
+
+        public void Draw(TextDrawingRequest request)
+        {
+            request.Canvas.Translate(new Position(0, request.TotalAscent));
+            request.Canvas.DrawExternalLink(Url, new Size(request.TextSize.Width, request.TextSize.Height));
+            request.Canvas.Translate(new Position(0, -request.TotalAscent));
+            
+            GetItem().Draw(request);
+        }
+
+        private TextItem GetItem()
+        {
+            return new TextItem
+            {
+                Style = Style,
+                Text = Text
+            };
+        }
+    }
 }

+ 40 - 2
QuestPDF/Fluent/TextExtensions.cs

@@ -10,9 +10,15 @@ namespace QuestPDF.Fluent
     public class TextDescriptor
     {
         private ICollection<TextBlock> TextBlocks { get; } = new List<TextBlock>();
+        private TextStyle DefaultStyle { get; set; } = TextStyle.Default;
         private HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
         private float Spacing { get; set; } = 0f;
 
+        public void DefaultTextStyle(TextStyle style)
+        {
+            DefaultStyle = style;
+        }
+        
         public void AlignLeft()
         {
             Alignment = HorizontalAlignment.Left;
@@ -35,7 +41,7 @@ namespace QuestPDF.Fluent
         
         public void Span(string text, TextStyle? style = null)
         {
-            style ??= TextStyle.Default;
+            style ??= DefaultStyle;
             
             if (string.IsNullOrWhiteSpace(text))
                 return;
@@ -71,7 +77,7 @@ namespace QuestPDF.Fluent
 
         private void PageNumber(string slotName, TextStyle? style = null)
         {
-            style ??= TextStyle.Default;
+            style ??= DefaultStyle;
             
             if (!TextBlocks.Any())
                 TextBlocks.Add(new TextBlock());
@@ -98,8 +104,40 @@ namespace QuestPDF.Fluent
             PageNumber(locationName, style);
         }
         
+        public void InternalLocation(string text, string locationName, TextStyle? style = null)
+        {
+            style ??= DefaultStyle;
+            
+            if (!TextBlocks.Any())
+                TextBlocks.Add(new TextBlock());
+            
+            TextBlocks.First().Children.Add(new InternalLinkTextItem
+            {
+                Style = style,
+                Text = text,
+                LocationName = locationName
+            });
+        }
+        
+        public void ExternalLocation(string text, string url, TextStyle? style = null)
+        {
+            style ??= DefaultStyle;
+            
+            if (!TextBlocks.Any())
+                TextBlocks.Add(new TextBlock());
+            
+            TextBlocks.First().Children.Add(new ExternalLinkTextItem
+            {
+                Style = style,
+                Text = text,
+                Url = url
+            });
+        }
+        
         internal void Compose(IContainer container)
         {
+            TextBlocks.ToList().ForEach(x => x.Alignment = Alignment);
+            
             container.Stack(stack =>
             {
                 stack.Spacing(Spacing);