62 lines
3.0 KiB
C#
62 lines
3.0 KiB
C#
namespace LehrerApp.Templating;
|
||
|
||
/// <summary>Lesbare, umbrechende Textblöcke für Berichtsbausteine. Jede Zeile ist ein eigener
|
||
/// Zeichenbefehl, damit FLOWDRAWBOX auch lange Berichte an Zeilengrenzen aufteilen kann.</summary>
|
||
public static class ReportTextDrawing
|
||
{
|
||
public const string RepeatInfo = "Exam.RepeatInfo";
|
||
public const string InterimGrades = "Student.InterimGrades";
|
||
|
||
public static DrawingValue Build(string title, IEnumerable<string> paragraphs,
|
||
float width = 170, float scale = 1, float pageHeight = 240, bool fixedBox = false)
|
||
{
|
||
if (!float.IsFinite(width) || !float.IsFinite(scale) || !float.IsFinite(pageHeight)
|
||
|| scale <= 0 || width < 20 * scale || pageHeight < 12 * scale)
|
||
throw new InvalidDataException("Der Berichtsbaustein benötigt mindestens 20 × 12 mm Platz.");
|
||
var commands = new List<DrawingCommand>();
|
||
var lineHeight = 5f * scale;
|
||
var y = 0f;
|
||
// Konservative Zeichenbreiten in Gevierten der Standardschrift. Breite Buchstaben
|
||
// bekommen mehr Raum; auch einzelne überlange Wörter werden umgebrochen.
|
||
var available = (width - 2 * scale) / (10 * 25.4f / 72 * scale);
|
||
static float Advance(char c) => char.IsWhiteSpace(c) ? .4f
|
||
: c is 'm' or 'w' or 'M' or 'W' ? 1.1f
|
||
: c > 255 ? 1.1f : char.IsUpper(c) ? 1f : .7f;
|
||
void Line(string text, bool bold)
|
||
{
|
||
var offset = y % pageHeight;
|
||
if (offset + lineHeight > pageHeight + .001f) y += pageHeight - offset;
|
||
if (fixedBox && y + lineHeight > pageHeight + .001f)
|
||
throw new InvalidDataException("Der Berichtsbaustein passt nicht in die feste DRAWBOX. Bitte FLOWDRAWBOX verwenden oder die Box vergrößern.");
|
||
commands.Add(new DrawStringEx(scale, y, lineHeight, width - 2 * scale, text,
|
||
DrawingTextAlignment.AlignLeft, 10, Bold: bold));
|
||
y += lineHeight;
|
||
}
|
||
foreach (var paragraph in new[] { title }.Concat(paragraphs))
|
||
{
|
||
foreach (var original in paragraph.Replace("\r\n", "\n").Split('\n'))
|
||
{
|
||
var remaining = original.Trim();
|
||
if (remaining.Length == 0) { Line("", false); continue; }
|
||
while (remaining.Length > 0)
|
||
{
|
||
var length = 0;
|
||
var used = 0f;
|
||
while (length < remaining.Length && used + Advance(remaining[length]) <= available)
|
||
used += Advance(remaining[length++]);
|
||
length = Math.Max(1, length);
|
||
var cut = length;
|
||
if (length < remaining.Length)
|
||
{
|
||
var space = remaining.LastIndexOf(' ', length - 1, length);
|
||
if (space > 0) cut = space;
|
||
}
|
||
Line(remaining[..cut], paragraph == title);
|
||
remaining = remaining[cut..].TrimStart();
|
||
}
|
||
}
|
||
}
|
||
return new DrawingValue(commands, y);
|
||
}
|
||
}
|