Rendering text paragraphs without the Column element (not fully working)
This commit is contained in:
@@ -19,5 +19,6 @@ namespace QuestPDF.Elements.Text.Calculation
|
||||
public int TotalIndex { get; set; }
|
||||
|
||||
public bool IsLast => EndIndex == TotalIndex;
|
||||
public bool IsNewLine { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -39,18 +39,34 @@ namespace QuestPDF.Elements.Text.Items
|
||||
|
||||
var paint = Style.ToPaint();
|
||||
var fontMetrics = Style.ToFontMetrics();
|
||||
var spaceCodepoint = paint.ToFont().Typeface.GetGlyphs(" ")[0];
|
||||
|
||||
// if the element is the first one within the line,
|
||||
// ignore leading spaces and new lines
|
||||
var spaceCodepoint = paint.ToFont().Typeface.GetGlyph(' ');
|
||||
var newLineCodepoint = paint.ToFont().Typeface.GetGlyph('\n');
|
||||
var returnCodepoint = paint.ToFont().Typeface.GetGlyph('\r');
|
||||
|
||||
var startIndex = request.StartIndex;
|
||||
|
||||
// if the element is the first one within the line,
|
||||
// ignore leading spaces
|
||||
if (!request.IsFirstElementInBlock && request.IsFirstElementInLine)
|
||||
{
|
||||
while (startIndex < TextShapingResult.Glyphs.Length && Text[startIndex] == spaceCodepoint)
|
||||
while (startIndex < TextShapingResult.Glyphs.Length && (Text[startIndex] == spaceCodepoint || Text[startIndex] == newLineCodepoint || Text[startIndex] == returnCodepoint))
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
// calculate max index (new new line)
|
||||
var newLineIndex = startIndex;
|
||||
|
||||
while (newLineIndex < TextShapingResult.Glyphs.Length)
|
||||
{
|
||||
var glyphCodepoint = TextShapingResult.Glyphs[newLineIndex].Codepoint;
|
||||
|
||||
if (glyphCodepoint == newLineCodepoint || glyphCodepoint == returnCodepoint)
|
||||
break;
|
||||
|
||||
newLineIndex++;
|
||||
}
|
||||
|
||||
if (TextShapingResult.Glyphs.Length == 0 || startIndex == TextShapingResult.Glyphs.Length)
|
||||
{
|
||||
return new TextMeasurementResult
|
||||
@@ -68,6 +84,8 @@ namespace QuestPDF.Elements.Text.Items
|
||||
|
||||
if (endIndex < startIndex)
|
||||
return null;
|
||||
|
||||
endIndex = Math.Min(endIndex, newLineIndex);
|
||||
|
||||
// break text only on spaces
|
||||
var wrappedText = WrapText(startIndex, endIndex, request.IsFirstElementInLine);
|
||||
@@ -90,7 +108,9 @@ namespace QuestPDF.Elements.Text.Items
|
||||
StartIndex = startIndex,
|
||||
EndIndex = wrappedText.Value.endIndex,
|
||||
NextIndex = wrappedText.Value.nextIndex,
|
||||
TotalIndex = TextShapingResult.Glyphs.Length - 1
|
||||
TotalIndex = TextShapingResult.Glyphs.Length - 1,
|
||||
|
||||
IsNewLine = endIndex == newLineIndex
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace QuestPDF.Elements.Text
|
||||
internal class TextBlock : Element, IStateResettable
|
||||
{
|
||||
public HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
|
||||
public List<ITextBlockItem> Items { get; set; } = new List<ITextBlockItem>();
|
||||
public List<ITextBlockItem> Items { get; set; } = new();
|
||||
public float ParagraphSpacing { get; set; } = 0;
|
||||
|
||||
public string Text => string.Join(" ", Items.Where(x => x is TextBlockSpan).Cast<TextBlockSpan>().Select(x => x.Text));
|
||||
|
||||
@@ -110,6 +111,12 @@ namespace QuestPDF.Elements.Text
|
||||
Canvas.Translate(new Position(0, line.LineHeight));
|
||||
|
||||
heightOffset += line.LineHeight;
|
||||
|
||||
if (line.Elements.Last().Measurement.IsNewLine)
|
||||
{
|
||||
heightOffset += ParagraphSpacing;
|
||||
Canvas.Translate(new Position(0, ParagraphSpacing));
|
||||
}
|
||||
}
|
||||
|
||||
Canvas.Translate(new Position(0, -heightOffset));
|
||||
|
||||
@@ -40,10 +40,9 @@ namespace QuestPDF.Fluent
|
||||
|
||||
public class TextDescriptor
|
||||
{
|
||||
private ICollection<TextBlock> TextBlocks { get; } = new List<TextBlock>();
|
||||
internal TextBlock TextBlock = new();
|
||||
private TextStyle DefaultStyle { get; set; } = TextStyle.Default;
|
||||
internal HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
|
||||
private float Spacing { get; set; } = 0f;
|
||||
|
||||
public void DefaultTextStyle(TextStyle style)
|
||||
{
|
||||
@@ -72,17 +71,9 @@ namespace QuestPDF.Fluent
|
||||
|
||||
public void ParagraphSpacing(float value, Unit unit = Unit.Point)
|
||||
{
|
||||
Spacing = value.ToPoints(unit);
|
||||
TextBlock.ParagraphSpacing = value.ToPoints(unit);
|
||||
}
|
||||
|
||||
private void AddItemToLastTextBlock(ITextBlockItem item)
|
||||
{
|
||||
if (!TextBlocks.Any())
|
||||
TextBlocks.Add(new TextBlock());
|
||||
|
||||
TextBlocks.Last().Items.Add(item);
|
||||
}
|
||||
|
||||
[Obsolete("This element has been renamed since version 2022.3. Please use the overload that returns a TextSpanDescriptor object which allows to specify text style.")]
|
||||
public void Span(string? text, TextStyle style)
|
||||
{
|
||||
@@ -96,28 +87,13 @@ namespace QuestPDF.Fluent
|
||||
|
||||
if (text == null)
|
||||
return descriptor;
|
||||
|
||||
var items = text
|
||||
.Replace("\r", string.Empty)
|
||||
.Split(new[] { '\n' }, StringSplitOptions.None)
|
||||
.Select(x => new TextBlockSpan
|
||||
{
|
||||
Text = x,
|
||||
Style = style
|
||||
})
|
||||
.ToList();
|
||||
|
||||
AddItemToLastTextBlock(items.First());
|
||||
|
||||
items
|
||||
.Skip(1)
|
||||
.Select(x => new TextBlock
|
||||
{
|
||||
Items = new List<ITextBlockItem> { x }
|
||||
})
|
||||
.ToList()
|
||||
.ForEach(TextBlocks.Add);
|
||||
|
||||
|
||||
TextBlock.Items.Add(new TextBlockSpan
|
||||
{
|
||||
Text = text,
|
||||
Style = style
|
||||
});
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@@ -137,7 +113,7 @@ namespace QuestPDF.Fluent
|
||||
var style = DefaultStyle.Clone();
|
||||
var descriptor = new TextPageNumberDescriptor(style);
|
||||
|
||||
AddItemToLastTextBlock(new TextBlockPageNumber
|
||||
TextBlock.Items.Add(new TextBlockPageNumber
|
||||
{
|
||||
Source = context => descriptor.FormatFunction(pageNumber(context)),
|
||||
Style = style
|
||||
@@ -193,7 +169,7 @@ namespace QuestPDF.Fluent
|
||||
if (IsNullOrEmpty(text))
|
||||
return descriptor;
|
||||
|
||||
AddItemToLastTextBlock(new TextBlockSectionLink
|
||||
TextBlock.Items.Add(new TextBlockSectionLink
|
||||
{
|
||||
Style = style,
|
||||
Text = text,
|
||||
@@ -220,7 +196,7 @@ namespace QuestPDF.Fluent
|
||||
if (IsNullOrEmpty(text))
|
||||
return descriptor;
|
||||
|
||||
AddItemToLastTextBlock(new TextBlockHyperlink
|
||||
TextBlock.Items.Add(new TextBlockHyperlink
|
||||
{
|
||||
Style = style,
|
||||
Text = text,
|
||||
@@ -240,26 +216,13 @@ namespace QuestPDF.Fluent
|
||||
{
|
||||
var container = new Container();
|
||||
|
||||
AddItemToLastTextBlock(new TextBlockElement
|
||||
TextBlock.Items.Add(new TextBlockElement
|
||||
{
|
||||
Element = container
|
||||
});
|
||||
|
||||
return container.AlignBottom().MinimalBox();
|
||||
}
|
||||
|
||||
internal void Compose(IContainer container)
|
||||
{
|
||||
TextBlocks.ToList().ForEach(x => x.Alignment = Alignment);
|
||||
|
||||
container.DefaultTextStyle(DefaultStyle).Column(column =>
|
||||
{
|
||||
column.Spacing(Spacing);
|
||||
|
||||
foreach (var textBlock in TextBlocks)
|
||||
column.Item().Element(textBlock);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class TextExtensions
|
||||
@@ -272,7 +235,7 @@ namespace QuestPDF.Fluent
|
||||
descriptor.Alignment = alignment.Horizontal;
|
||||
|
||||
content?.Invoke(descriptor);
|
||||
descriptor.Compose(element);
|
||||
element.Element(descriptor.TextBlock);
|
||||
}
|
||||
|
||||
[Obsolete("This element has been renamed since version 2022.3. Please use the overload that returns a TextSpanDescriptor object which allows to specify text style.")]
|
||||
|
||||
Reference in New Issue
Block a user