276 lines
8.1 KiB
C#
276 lines
8.1 KiB
C#
namespace Inspectron.Epson.TemplateEngine.Rendering;
|
|
|
|
public class LayoutEngine
|
|
{
|
|
public string AlignText(string text, string alignment, int lineWidth)
|
|
{
|
|
if (string.IsNullOrEmpty(text))
|
|
return text ?? "";
|
|
|
|
if (text.Length >= lineWidth)
|
|
return text;
|
|
|
|
return alignment.ToLowerInvariant() switch
|
|
{
|
|
"center" => CenterText(text, lineWidth),
|
|
"right" => text.PadLeft(lineWidth),
|
|
_ => text // left-aligned is default (no padding)
|
|
};
|
|
}
|
|
|
|
private static string CenterText(string text, int lineWidth)
|
|
{
|
|
int totalPadding = lineWidth - text.Length;
|
|
int leftPadding = totalPadding / 2;
|
|
return new string(' ', leftPadding) + text;
|
|
}
|
|
|
|
public string FormatTwoColumns(string left, string right, int lineWidth)
|
|
{
|
|
left ??= "";
|
|
right ??= "";
|
|
|
|
int halfWidth = lineWidth / 2;
|
|
return left.PadRight(halfWidth) + right.PadLeft(lineWidth - halfWidth);
|
|
}
|
|
|
|
public List<string> FormatTwoColumnsWithWrap(string left, string right, int lineWidth)
|
|
{
|
|
left ??= "";
|
|
right ??= "";
|
|
|
|
int halfWidth = lineWidth / 2;
|
|
|
|
// Try simple format first
|
|
if (left.Length + right.Length <= lineWidth)
|
|
{
|
|
int spaces = lineWidth - left.Length - right.Length;
|
|
if (spaces < 1) spaces = 1;
|
|
return new List<string> { left + new string(' ', spaces) + right };
|
|
}
|
|
|
|
// Wrap left side, right-align right on first line
|
|
var leftLines = WrapText(left, halfWidth);
|
|
var result = new List<string>();
|
|
|
|
for (int i = 0; i < leftLines.Count; i++)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
int spaces = lineWidth - leftLines[i].Length - right.Length;
|
|
if (spaces < 1)
|
|
{
|
|
result.Add(leftLines[i]);
|
|
result.Add(right.PadLeft(lineWidth));
|
|
}
|
|
else
|
|
{
|
|
result.Add(leftLines[i] + new string(' ', spaces) + right);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.Add(leftLines[i]);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public string FormatMultiColumn(List<(string text, int width, string align)> columns, int lineWidth)
|
|
{
|
|
var parts = new List<string>();
|
|
|
|
// Calculate widths: distribute remaining width among columns without explicit width
|
|
int totalExplicit = columns.Where(c => c.width > 0).Sum(c => c.width);
|
|
int unspecifiedCount = columns.Count(c => c.width <= 0);
|
|
int remaining = lineWidth - totalExplicit;
|
|
int defaultWidth = unspecifiedCount > 0 ? remaining / unspecifiedCount : 0;
|
|
|
|
foreach (var (text, width, align) in columns)
|
|
{
|
|
int colWidth = width > 0 ? width : defaultWidth;
|
|
if (colWidth <= 0) colWidth = 1;
|
|
|
|
string formatted = align.ToLowerInvariant() switch
|
|
{
|
|
"center" => CenterInWidth(text ?? "", colWidth),
|
|
"right" => (text ?? "").PadLeft(colWidth),
|
|
_ => (text ?? "").PadRight(colWidth)
|
|
};
|
|
|
|
// Truncate if too long
|
|
if (formatted.Length > colWidth)
|
|
formatted = formatted[..colWidth];
|
|
|
|
parts.Add(formatted);
|
|
}
|
|
|
|
return string.Concat(parts);
|
|
}
|
|
|
|
public List<string> WrapText(string text, int maxWidth, int indent = 0)
|
|
{
|
|
var lines = new List<string>();
|
|
|
|
if (string.IsNullOrEmpty(text) || maxWidth <= 0)
|
|
{
|
|
lines.Add(text ?? "");
|
|
return lines;
|
|
}
|
|
|
|
if (text.Length <= maxWidth)
|
|
{
|
|
lines.Add(text);
|
|
return lines;
|
|
}
|
|
|
|
var words = text.Split(' ');
|
|
string currentLine = "";
|
|
bool isFirst = true;
|
|
|
|
foreach (var word in words)
|
|
{
|
|
int available = isFirst ? maxWidth : maxWidth - indent;
|
|
if (available <= 0) available = 1;
|
|
|
|
if (currentLine.Length == 0)
|
|
{
|
|
currentLine = word;
|
|
}
|
|
else if (currentLine.Length + 1 + word.Length <= available)
|
|
{
|
|
currentLine += " " + word;
|
|
}
|
|
else
|
|
{
|
|
if (isFirst)
|
|
{
|
|
lines.Add(currentLine);
|
|
isFirst = false;
|
|
}
|
|
else
|
|
{
|
|
lines.Add(new string(' ', indent) + currentLine);
|
|
}
|
|
currentLine = word;
|
|
}
|
|
}
|
|
|
|
if (currentLine.Length > 0)
|
|
{
|
|
if (isFirst)
|
|
lines.Add(currentLine);
|
|
else
|
|
lines.Add(new string(' ', indent) + currentLine);
|
|
}
|
|
|
|
return lines;
|
|
}
|
|
|
|
public string CreateSeparator(char character, int lineWidth)
|
|
{
|
|
return new string(character, lineWidth);
|
|
}
|
|
|
|
public List<string> FormatTable(
|
|
List<(string text, int width, string align)> columns,
|
|
List<List<string>> headerRows,
|
|
List<List<string>> dataRows,
|
|
int lineWidth)
|
|
{
|
|
var result = new List<string>();
|
|
|
|
// Calculate column widths
|
|
var colWidths = CalculateTableColumnWidths(columns, lineWidth);
|
|
|
|
// Top border
|
|
result.Add(FormatTableBorder(colWidths));
|
|
|
|
// Header rows
|
|
foreach (var row in headerRows)
|
|
{
|
|
result.Add(FormatTableRow(row, colWidths, columns));
|
|
}
|
|
|
|
// Separator between header and data
|
|
if (headerRows.Count > 0 && dataRows.Count > 0)
|
|
{
|
|
result.Add(FormatTableBorder(colWidths));
|
|
}
|
|
|
|
// Data rows
|
|
foreach (var row in dataRows)
|
|
{
|
|
result.Add(FormatTableRow(row, colWidths, columns));
|
|
}
|
|
|
|
// Bottom border
|
|
result.Add(FormatTableBorder(colWidths));
|
|
|
|
return result;
|
|
}
|
|
|
|
private List<int> CalculateTableColumnWidths(List<(string text, int width, string align)> columns, int lineWidth)
|
|
{
|
|
// Account for borders: |col1|col2|col3| = columns.Count + 1 border chars
|
|
int availableWidth = lineWidth - columns.Count - 1;
|
|
int totalExplicit = columns.Where(c => c.width > 0).Sum(c => c.width);
|
|
int unspecifiedCount = columns.Count(c => c.width <= 0);
|
|
int remaining = availableWidth - totalExplicit;
|
|
int defaultWidth = unspecifiedCount > 0 ? remaining / unspecifiedCount : 0;
|
|
|
|
var widths = new List<int>();
|
|
foreach (var (_, width, _) in columns)
|
|
{
|
|
widths.Add(width > 0 ? width : Math.Max(defaultWidth, 1));
|
|
}
|
|
return widths;
|
|
}
|
|
|
|
private string FormatTableBorder(List<int> colWidths)
|
|
{
|
|
return "+" + string.Join("+", colWidths.Select(w => new string('-', w))) + "+";
|
|
}
|
|
|
|
private string FormatTableRow(List<string> cells, List<int> colWidths, List<(string text, int width, string align)> columns)
|
|
{
|
|
var parts = new List<string>();
|
|
for (int i = 0; i < colWidths.Count; i++)
|
|
{
|
|
string cell = i < cells.Count ? cells[i] : "";
|
|
string align = i < columns.Count ? columns[i].align : "left";
|
|
parts.Add(FormatCellContent(cell, colWidths[i], align));
|
|
}
|
|
return "|" + string.Join("|", parts) + "|";
|
|
}
|
|
|
|
private string FormatCellContent(string text, int width, string align)
|
|
{
|
|
if (text.Length > width)
|
|
text = text[..width];
|
|
|
|
return align.ToLowerInvariant() switch
|
|
{
|
|
"center" => CenterInWidth(text, width),
|
|
"right" => text.PadLeft(width),
|
|
_ => text.PadRight(width)
|
|
};
|
|
}
|
|
|
|
private static string CenterInWidth(string text, int width)
|
|
{
|
|
if (string.IsNullOrEmpty(text))
|
|
return new string(' ', width);
|
|
|
|
if (text.Length >= width)
|
|
return text[..width];
|
|
|
|
int totalPadding = width - text.Length;
|
|
int leftPadding = totalPadding / 2;
|
|
int rightPadding = totalPadding - leftPadding;
|
|
|
|
return new string(' ', leftPadding) + text + new string(' ', rightPadding);
|
|
}
|
|
}
|