StatementTable.cs
// 
// このコードは、DioDocs for PDF のサンプルの一部として提供されています。
// © MESCIUS inc. All rights reserved.
// 
using System;
using System.IO;
using System.Drawing;
using System.Numerics;
using System.Collections.Generic;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Layout;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;

namespace DsPdfWeb.Demos
{
    // このサンプルでは、GrapeCity.Documents.Drawing.TableRenderer クラスを使用して、
    // 会計書類や請求書でよく使用されるレイアウトのドキュメントを描画する方法を紹介しています。
    public class StatementTable
    {
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            var p = doc.NewPage();
            p.Size = new SizeF(p.Size.Height, p.Size.Width);
            var g = p.Graphics;

            DrawTable(g, g.CanvasSize.Width, g.CanvasSize.Height);

            // PDF を保存します。
            doc.Save(stream);
            return doc.Pages.Count;
        }

        class InfoLine
        {
            public InfoLine(int indent, string text, int sum2021, int sum2020, int sum2019, bool boldText = false,
                bool captionOnly = false, bool drawSign = false, bool thinLine = false, bool boldLine = false)
            {
                Indent = indent;
                Text = text;
                Sum2021 = sum2021;
                Sum2020 = sum2020;
                Sum2019 = sum2019;
                BoldText = boldText;
                CaptionOnly = captionOnly;
                DrawSign = drawSign;
                ThinLine = thinLine;
                BoldLine = boldLine;
            }
            public int Indent { get; }
            public string Text { get; }
            public int Sum2021 { get; }
            public int Sum2020 { get; }
            public int Sum2019 { get; }
            public bool BoldText { get; }
            public bool CaptionOnly { get; }
            public bool DrawSign { get; }
            public bool ThinLine { get; }
            public bool BoldLine { get; }
        }

        static void DrawTable(GcGraphics g, float pageWidth, float pageHeight)
        {
            var items = new InfoLine[]
            {
                new InfoLine(0, "売上高:", 0, 0, 0, captionOnly: true),
                new InfoLine(1, "製品", 297392, 220747, 213883, drawSign: true),
                new InfoLine(1, "サービス", 68425, 53768, 46291, thinLine: true),
                new InfoLine(2, "売上高合計", 365817, 274515, 260174, boldText: true),
                new InfoLine(0, "売上原価:", 0, 0, 0, captionOnly: true),
                new InfoLine(1, "製品", 192266, 151286, 144996),
                new InfoLine(1, "サービス", 20715, 18273, 16786, thinLine: true),
                new InfoLine(2, "売上原価合計", 212981, 169559, 161782, boldText: true, thinLine: true),
                new InfoLine(3, "売上総利益", 152836, 104956, 98392, boldText: true, thinLine: true),
                new InfoLine(0, "営業費用:", 0, 0, 0, captionOnly: true),
                new InfoLine(1, "研究開発費", 21914, 18752, 16217),
                new InfoLine(1, "販売費および一般管理費", 21973, 19916, 18245, thinLine: true),
                new InfoLine(2, "営業費用合計", 43887, 38668, 34462, boldText: true, thinLine: true),
                new InfoLine(0, " ", 0, 0, 0, captionOnly: true),
                new InfoLine(0, "営業利益", 108949, 66288, 63930),
                new InfoLine(0, "その他の収益・費用(△)", 258, 803, 1807, thinLine: true),
                new InfoLine(0, "税金等調整前当期純利益", 109207, 67091, 65737, boldText: true),
                new InfoLine(0, "法人税等調整額", 14527, 9680, 10481, thinLine: true),
                new InfoLine(0, "当期純利益", 94680, 57411, 55256, boldText: true, drawSign: true, boldLine: true),
            };

            var host = new LayoutHost();
            var view = host.CreateView(pageWidth, pageHeight);

            var rt = view.CreateRect();
            rt.AnchorTopLeft(null, 36, 36);

            var ta = new TableRenderer(g,
                rt, FixedTableSides.TopLeft,
                rowCount: items.Length + 3,
                columnCount: 7,
                gridLineColor: Color.Transparent,
                gridLineWidth: 0);

            var columns = ta.ColumnRects;
            columns[0].SetWidth(320);
            columns[1].SetWidth(25);
            columns[2].SetWidth(100);
            columns[3].SetWidth(25);
            columns[4].SetWidth(100);
            columns[5].SetWidth(25);
            columns[6].SetWidth(100);

            var fmt = new TextFormat
            {
                Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "ipag.ttc")),
                ForeColor = Color.FromArgb(38, 38, 38),
                FontSize = 11,
                FontSizeInGraphicUnits = true,
            };
            var fmtCaptionBold = new TextFormat(fmt)
            {
                FontBold = true,
                FontSize = 12
            };
            var fmtCaptionLight = new TextFormat(fmt)
            {
                ForeColor = Color.FromArgb(142, 142, 142),
                FontSize = 12
            };
            var fmtBold = new TextFormat(fmt)
            {
                FontBold = true
            };

            var csHeader1 = new CellStyle
            {
                TextAlignment = TextAlignment.Center,
                PaddingBottom = 25,
                CreateTextLayout = (g, cs, data) =>
                {
                    var tl = g.CreateTextLayout();
                    tl.AppendLine("DioDocs Inc.\n\n連結損益計算書", fmtCaptionBold);
                    tl.Append("(単位:百万ドル)", fmtCaptionLight);
                    return tl;
                }
            };
            ta.AddCell(csHeader1, 0, 0, 1, 7, null);

            var csThinLine = new CellStyle
            {
                Background = true,
                Borders = FrameBorders.BottomBorder,
                LinePaddingBottom = -1,
                LineWidth = 1
            };
            var csBoldLine = new CellStyle(csThinLine)
            {
                LinePaddingBottom = -3,
                LineWidth = 3
            };

            var csHeader2 = new CellStyle(csThinLine)
            {
                PaddingBottom = 5,
                TextAlignment = TextAlignment.Center,
                TextFormat = fmtBold
            };
            ta.AddCell(csHeader2, 1, 1, 1, 6, "連結決算日");
            ta.SetHorizontalGridLineWidth(2, 1);

            var csHeader3 = new CellStyle
            {
                PaddingTopBottom = 5,
                TextAlignment = TextAlignment.Center,
                TextFormat = fmtBold
            };
            ta.AddCell(csHeader3, 2, 1, 1, 2, "2021年\n9月25日");
            ta.AddCell(csHeader3, 2, 3, 1, 2, "2020年\n9月26日");
            ta.AddCell(csHeader3, 2, 5, 1, 2, "2019年\n9月28日");
            ta.AddCell(csThinLine, 2, 1, 1, 6);
            ta.SetHorizontalGridLineWidth(3, 1);

            var csText = new CellStyle
            {
                TextFormat = fmt,
                TextAlignment = TextAlignment.Leading,
                PaddingTopBottom = 4
            };
            var csBoldText = new CellStyle(csText)
            {
                TextFormat = fmtBold
            };
            var csNum = new CellStyle
            {
                TextFormat = fmt,
                TextAlignment = TextAlignment.Trailing,
                PaddingTopBottom = 4,
                PaddingRight = 10
            };
            var csBoldNum = new CellStyle(csNum)
            {
                TextFormat = fmtBold
            };
            var csBand = new CellStyle
            {
                FillColor = Color.FromArgb(245, 245, 245),
                Background = true
            };

            for (int i = 0; i < items.Length; i++)
            {
                var item = items[i];
                int rowIndex = i + 3;

                if ((i & 1) != 0)
                {
                    ta.AddCell(csBand, rowIndex, 0, 1, 7);
                }

                var tc = ta.AddCell(item.BoldText ? csBoldText : csText, rowIndex, 0, item.Text);
                tc.TextLayout.FirstLineIndent = item.Indent * 8 + 10;

                var csCurrNum = item.BoldText ? csBoldNum : csNum;
                if (item.DrawSign)
                {
                    ta.AddCell(csCurrNum, rowIndex, 1, "$");
                    ta.AddCell(csCurrNum, rowIndex, 3, "$");
                    ta.AddCell(csCurrNum, rowIndex, 5, "$");
                }
                if (!item.CaptionOnly)
                {
                    ta.AddCell(csCurrNum, rowIndex, 2, item.Sum2021.ToString("n0"));
                    ta.AddCell(csCurrNum, rowIndex, 4, item.Sum2020.ToString("n0"));
                    ta.AddCell(csCurrNum, rowIndex, 6, item.Sum2019.ToString("n0"));
                }

                if (item.ThinLine)
                {
                    ta.AddCell(csThinLine, rowIndex, 1, 1, 6);
                    ta.SetHorizontalGridLineWidth(rowIndex + 1, 1);
                }
                else if (item.BoldLine)
                {
                    ta.AddCell(csBoldLine, rowIndex, 1, 1, 6);
                    ta.SetHorizontalGridLineWidth(rowIndex + 1, 3);
                }
            }

            ta.Render();
        }
    }
}