tbf/Results/Output/Printers/PrintersCommon.cs

226 lines
9.6 KiB
C#
Raw Normal View History

2018-03-06 17:37:43 +00:00
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using Config.Entities;
namespace Results.Output.Printers
{
public enum TableLines
{
None,
FirstAndLast,
FirstSecondAndLast,
All,
}
public class TableStyle
{
public float MarginX;
public float MarginY;
public Font Font;
public Font HeaderFont;
public int TopHeadersCount;
public int LeftHeadersCount;
public float LineWidth;
public TableLines HorizLines;
public TableLines VertLines;
}
public class PrintersCommon : PrintDocument
{
protected SizeF MeasureTable(System.Drawing.Printing.PrintPageEventArgs e, IList<string[]> rows, TableStyle tableStyle)
{
SizeF retVal = new SizeF(0, 0);
if (rows == null || rows.Count == 0) return retVal;
int tblColumnsCount = rows[0].Length;
float[] columnWidth = new float[tblColumnsCount];
float[] rowHeight = new float[rows.Count];
///
/// Measure table column widths and header height
///
for (int colIx = 0; colIx < tblColumnsCount; colIx++)
{
for (int rowIx = 0; rowIx < rows.Count; rowIx++)
{
bool isHeader = (colIx < tableStyle.LeftHeadersCount) || (rowIx < tableStyle.TopHeadersCount);
SizeF size = Measure(e, rows[rowIx][colIx], isHeader ? tableStyle.HeaderFont : tableStyle.Font);
if (size.Width > columnWidth[colIx]) columnWidth[colIx] = size.Width;
if (size.Height > rowHeight[rowIx]) rowHeight[rowIx] = size.Height;
}
retVal.Width += columnWidth[colIx] + 2 * tableStyle.MarginX;
}
for (int rowIx = 0; rowIx < rows.Count; rowIx++)
{
retVal.Height += rowHeight[rowIx] + 2 * tableStyle.MarginY;
}
return retVal;
}
protected float DrawTable(System.Drawing.Printing.PrintPageEventArgs e, float left, float top, IList<string[]> rows,
IList<Alignment[]> horizAlignments, IList<VertAlignment[]> vertAlignments, TableStyle tableStyle)
{
if (rows == null || rows.Count == 0) return top;
int tblColumnsCount = rows[0].Length;
float[] columnWidth = new float[tblColumnsCount];
float[] columnPos = new float[tblColumnsCount + 1];
float[] rowHeight = new float[rows.Count];
float[] rowPos = new float[rows.Count + 1];
///
/// Measure table column widths and header height
///
columnPos[0] = left;
rowPos[0] = top;
for (int colIx = 0; colIx < tblColumnsCount; colIx++)
{
for (int rowIx = 0; rowIx < rows.Count; rowIx++)
{
bool isHeader = (colIx < tableStyle.LeftHeadersCount) || (rowIx < tableStyle.TopHeadersCount);
SizeF size = Measure(e, rows[rowIx][colIx], isHeader ? tableStyle.HeaderFont : tableStyle.Font);
if (size.Width > columnWidth[colIx]) columnWidth[colIx] = size.Width;
if (size.Height > rowHeight[rowIx]) rowHeight[rowIx] = size.Height;
}
columnPos[colIx + 1] = columnPos[colIx] + columnWidth[colIx] + 2 * tableStyle.MarginX + tableStyle.LineWidth;
}
for (int rowIx = 0; rowIx < rows.Count; rowIx++)
{
rowPos[rowIx + 1] = rowPos[rowIx] + rowHeight[rowIx] + 2 * tableStyle.MarginY + tableStyle.LineWidth;
}
/// Horizontal lines
float tableLeftX = left;
float tableRightX = columnPos[tblColumnsCount] + tableStyle.LineWidth;
if (tableStyle.HorizLines != TableLines.None)
{
for (int rowIx = 0; rowIx <= rows.Count; rowIx++)
{
if (tableStyle.HorizLines == TableLines.All || rowIx == 0 || rowIx == rows.Count || (tableStyle.HorizLines == TableLines.FirstSecondAndLast && rowIx == 1))
{
e.Graphics.DrawLine(new Pen(Color.Black, tableStyle.LineWidth), new PointF(tableLeftX, rowPos[rowIx] + tableStyle.LineWidth / 2), new PointF(tableRightX, rowPos[rowIx] + tableStyle.LineWidth / 2));
}
}
}
/// Vertical lines
float tableTopY = top;
float tableBottomY = rowPos[rows.Count] + tableStyle.LineWidth;
if (tableStyle.VertLines != TableLines.None)
{
for (int colIx = 0; colIx <= tblColumnsCount; colIx++)
{
if (tableStyle.VertLines == TableLines.All || colIx == 0 || colIx == rows.Count || (tableStyle.VertLines == TableLines.FirstSecondAndLast && colIx == 1))
{
e.Graphics.DrawLine(new Pen(Color.Black, tableStyle.LineWidth), new PointF(columnPos[colIx] + tableStyle.LineWidth / 2, tableTopY), new PointF(columnPos[colIx] + tableStyle.LineWidth / 2, tableBottomY));
}
}
}
///
/// Draw table body
///
for (int rowIndex = 0; rowIndex < rows.Count; rowIndex++)
{
string[] oneTableRow = rows[rowIndex];
Alignment[] horizAlignment = horizAlignments[(horizAlignments.Count > rowIndex) ? rowIndex : 0];
VertAlignment[] vertAlignment = vertAlignments[(vertAlignments.Count > rowIndex) ? rowIndex : 0];
for (int colIndex = 0; colIndex < tblColumnsCount; colIndex++)
{
bool isHeader = (colIndex < tableStyle.LeftHeadersCount) || (rowIndex < tableStyle.TopHeadersCount);
PrintAt(e, oneTableRow[colIndex],
isHeader ? tableStyle.HeaderFont : tableStyle.Font,
columnPos[colIndex] + tableStyle.MarginX + tableStyle.LineWidth,
rowPos[rowIndex] + tableStyle.MarginY,
columnWidth[colIndex],
rowHeight[rowIndex],
horizAlignment[colIndex],
vertAlignment[colIndex]);
}
}
return tableBottomY;
}
static Font lastFont = null;
static float lastSpacing = 0;
/// <summary>
/// Measure the size of a paragraph of text, lines are separated by '~'.
/// </summary>
/// <param name="e">PrintPageEventArgs</param>
/// <param name="text">Text, lines are separated by '~'</param>
/// <param name="font">Font</param>
/// <returns>Size of the paragraph of text</returns>
protected SizeF Measure(System.Drawing.Printing.PrintPageEventArgs e, string text, Font font)
{
if (font != lastFont)
{
lastFont = font;
lastSpacing = e.Graphics.MeasureString("Abcgq", font).Height;
}
string[] lines = text.Split(new char[] { '~' });
float width = 0;
foreach (var line in lines)
{
float lineWid = e.Graphics.MeasureString(line, font).Width;
if (lineWid > width) width = lineWid;
}
return new SizeF(width, 0.8f * lines.Length * lastSpacing + 0.2f);
}
/// <summary>
/// Print a paragraph of text, lines are separated by '~'.
/// </summary>
/// <param name="e">PrintPageEventArgs</param>
/// <param name="text">Text, lines are separated by '~'</param>
/// <param name="font">Font</param>
/// <param name="x">Position x</param>
/// <param name="y">Position y</param>
/// <param name="width">Width (required when alignment=Alignment.Center or alignment=Aligmenr.Right</param>
/// <param name="height">Height, 0 = no vertical centering</param>
/// <param name="horizAlignment">Horizontal alignment</param>
/// <param name="vertAlignment">Vertical alignment</param>
protected void PrintAt(System.Drawing.Printing.PrintPageEventArgs e, string text, Font font,
float x, float y, float width, float height, Alignment horizAlignment, VertAlignment vertAlignment)
{
SizeF size = Measure(e, text, font);
string[] lines = text.Split(new char[] { '~' });
if (height <= size.Height) vertAlignment = VertAlignment.Top;
float y0;
switch (vertAlignment)
{
default:
case VertAlignment.Top: y0 = y; break;
case VertAlignment.Middle: y0 = y + (height - size.Height) / 2; break;
case VertAlignment.Bottom: y0 = y + (height - size.Height); break;
}
foreach (var line in lines)
{
float x0;
switch (horizAlignment)
{
default:
case Alignment.Left: x0 = x; break;
case Alignment.Center: x0 = x + (width - e.Graphics.MeasureString(line, font).Width) / 2; break;
case Alignment.Right: x0 = x + width - e.Graphics.MeasureString(line, font).Width; break;
}
e.Graphics.DrawString(line, font, Brushes.Black, new PointF(x0, y0));
y0 += 0.8f * lastSpacing;
}
}
}
}