Files
QuestPDF/QuestPDF/Elements/Text.cs
T
2021-01-16 01:31:39 +01:00

117 lines
3.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using QuestPDF.Drawing;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Infrastructure;
using Size = QuestPDF.Infrastructure.Size;
namespace QuestPDF.Elements
{
internal class Text : Element
{
public string? Value { get; set; }
public TextStyle? Style { get; set; } = new TextStyle();
private float LineHeight => Style.Size * Style.LineHeight;
internal override ISpacePlan Measure(Size availableSpace)
{
var lines = BreakLines(availableSpace.Width);
var realWidth = lines
.Select(line => Style.BreakText(line, availableSpace.Width).FragmentWidth)
.DefaultIfEmpty(0)
.Max();
var realHeight = lines.Count * LineHeight;
if (realHeight > availableSpace.Height + Size.Epsilon)
return new Wrap();
return new FullRender(realWidth, realHeight);
}
internal override void Draw(ICanvas canvas, Size availableSpace)
{
var lines = BreakLines(availableSpace.Width);
var offsetTop = 0f;
var offsetLeft = GetLeftOffset();
canvas.Translate(new Position(0, Style.Size));
foreach (var line in lines)
{
canvas.DrawText(line, new Position(offsetLeft, offsetTop), Style);
offsetTop += LineHeight;
}
canvas.Translate(new Position(0, -Style.Size));
float GetLeftOffset()
{
return Style.Alignment switch
{
HorizontalAlignment.Left => 0,
HorizontalAlignment.Center => availableSpace.Width / 2,
HorizontalAlignment.Right => availableSpace.Width,
_ => throw new NotSupportedException()
};
}
}
#region Word Wrap
private List<string> BreakLines(float maxWidth)
{
var lines = new List<string> ();
var remainingText = Value.Trim();
while(true)
{
if (string.IsNullOrEmpty(remainingText))
break;
var breakPoint = BreakLinePoint(remainingText, maxWidth);
if (breakPoint == 0)
break;
var lastLine = remainingText.Substring(0, breakPoint).Trim();
lines.Add(lastLine);
remainingText = remainingText.Substring(breakPoint).Trim();
}
return lines;
}
private int BreakLinePoint(string text, float width)
{
var index = 0;
var lengthBreak = Style.BreakText(text, width).LineIndex;
while (index <= text.Length)
{
var next = text.IndexOfAny (new [] { ' ', '\n' }, index);
if (next <= 0)
return index == 0 || lengthBreak == text.Length ? lengthBreak : index;
if (next > lengthBreak)
return index;
if (text[next] == '\n')
return next;
index = next + 1;
}
return index;
}
#endregion
}
}