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

namespace DsPdfWeb.Demos.Basics
{
    // テキストの段落を DsPdf の番号付きリストとして描画する方法を示します。
    // このサンプル内におけるテキストのページを描画するメソッドは、PaginatedText サンプルから取得されます。
    // TextRendering も参照してください。
    public class NumberedList
    {
        // サンプルで使用されているページレイアウト定数をカプセル化します。
        private struct Layout
        {
            public static float Margin => 72;
            public static float ListOffset => 24;
        };

        // TextLayout 内のすべての段落の先頭に数値を付加するユーティリティメソッドです。
        private void AddBullets(GcGraphics g, PointF pt, TextLayout tl, ref int itemNo)
        {
            var tlBullet = g.CreateTextLayout();
            tlBullet.DefaultFormat.FontName = "Yu Gothic";
            tlBullet.DefaultFormat.FontSize = 12;
            foreach (var line in tl.Lines)
            {
                if (line.FirstLineInParagraph)
                {
                    tlBullet.Clear();
                    tlBullet.Append($"{itemNo++})");
                    tlBullet.PerformLayout(true);
                    g.DrawTextLayout(tlBullet, new PointF(pt.X, pt.Y + line.Position + line.LineGap));
                }
            }
        }

        // メインエントリポイントです。
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            var ip = new PointF(Layout.Margin, Layout.Margin);
            // TextLayout.MarginLeft を使用して、リスト番号/箇条書き用ののスペースを予約します。
            var tl = new TextLayout(72)
            {
                MaxWidth = doc.PageSize.Width - Layout.Margin * 2,
                MaxHeight = doc.PageSize.Height - Layout.Margin * 2,
                ParagraphSpacing = 8,
                MarginLeft = Layout.ListOffset,
            };
            tl.DefaultFormat.FontName = "Yu Gothic";

            // 20 項目の番号付きリストとして描画される 20 段落のテキストを追加します。
            tl.Append(Common.Util.getString_ja(0, 0, 20, 1, 6));
            // レイアウトを実行します。
            tl.PerformLayout(true);
            // 分割オプションを使用して、widow/orphan の制御を提供します。
            var to = new TextSplitOptions(tl);
            to.MinLinesInFirstParagraph = 2;
            to.MinLinesInLastParagraph = 2;
            // ループ内でテキストを分割して描画し(PaginatedText を参照)、
            // リスト番号を追加します。
            int itemNo = 1;
            while (true)
            {
                // 'rest' は、収まりきらなかったテキストを受け入れます。
                var splitResult = tl.Split(to, out TextLayout rest);
                var g = doc.Pages.Add().Graphics;
                g.DrawTextLayout(tl, ip);
                AddBullets(g, ip, tl, ref itemNo);
                if (splitResult != SplitResult.Split)
                    break;
                tl = rest;
            }
            // PDF ドキュメントを保存します。
            doc.Save(stream);
            return doc.Pages.Count;
        }
    }
}