NumberedList2.vb
'' 完毕:
Imports System.IO
Imports System.Drawing
Imports System.Text
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Drawing

'' 此示例演示了不同样式的编号列表如何
'' 可以在 GcDocs.Pdf 中呈现。
'' 另请参阅NumberedList。
Public Class NumberedList2
    '' 封装示例中使用的页面布局常量:
    Private Structure Layout
        '' 四周页边距:
        Public Shared Margin As Single = 72.0F
        '' 相对于项目编号的列表偏移量:
        Public Shared ListOffset As Single = 24.0F
        '' 列表级缩进:
        Public Shared ListIndent As Single = 30.0F
    End Structure

    '' 定义简单树类型:
    Private Class Node
        Public Sub New(ByVal txt As String)
            Text = txt
        End Sub
        Public Property Text As String
        Public Property Children As List(Of Node) = New List(Of Node)()
    End Class

    '' 将节点列表呈现为编号列表。
    Private Function RenderNodes(ByRef page As Page, ByVal pt As PointF, ByVal nodes As List(Of Node), ByVal level As Integer) As PointF

        Dim tlBullet = page.Graphics.CreateTextLayout()
        tlBullet.DefaultFormat.Font = StandardFonts.Times
        tlBullet.MarginLeft = Layout.ListIndent * level

        Dim tlText = New TextLayout(72)
        tlText.DefaultFormat.Font = StandardFonts.Times
        tlText.MarginLeft = Layout.ListOffset + Layout.ListIndent * level

        For i = 0 To nodes.Count - 1
            Dim g = page.Graphics
            '' 准备项目文本:
            tlText.Clear()
            tlText.Append(nodes(i).Text)
            tlText.PerformLayout(True)
            If pt.Y + tlText.ContentHeight > page.Size.Height - Layout.Margin Then
                page = page.Doc.NewPage()
                g = page.Graphics
                pt.Y = Layout.Margin
            End If
            '' 准备品编号:
            tlBullet.Clear()
            tlBullet.Append(ItemIdxToString(i, level, tlBullet))
            tlBullet.PerformLayout(True)
            '' 渲染项目:
            g.DrawTextLayout(tlBullet, pt)
            g.DrawTextLayout(tlText, pt)
            '' 提前插入点:
            pt.Y += tlText.ContentHeight
            '' 渲染子项:
            If nodes(i).Children.Count > 0 Then
                pt = RenderNodes(page, pt, nodes(i).Children, level + 1)
            End If
        Next
        Return pt
    End Function

    '' 将项目索引转换为项目编号表示形式
    '' 阿拉伯语 -> 拉丁字母 -> 罗马数字循环。
    '' 罗马数字右对齐,其他数字左对齐。
    Private Function ItemIdxToString(ByVal itemIdx As Integer, ByVal level As Integer, ByVal tl As TextLayout) As String

        Select Case (level Mod 3)
            Case 0
                tl.MarginLeft = Layout.ListIndent * level
                tl.MaxWidth = Nothing
                tl.TextAlignment = TextAlignment.Leading
                Return $"{itemIdx + 1}."
            Case 1
                tl.MarginLeft = Layout.ListIndent * level
                tl.MaxWidth = Nothing
                tl.TextAlignment = TextAlignment.Leading
                Return $"{ChrW(AscW("a") + itemIdx)}."
            Case 2
                tl.MarginLeft = 0
                Dim font = tl.DefaultFormat.Font
                tl.MaxWidth = Layout.ListIndent * level + tl.DefaultFormat.FontSize
                tl.TextAlignment = TextAlignment.Trailing
                Return $"{IntToRoman(itemIdx + 1)}."
            Case Else
                Throw New Exception("Unexpected.")
        End Select
    End Function

    '' 来自http://dotnet-snippets.com/snippet/roman-numerals/667
    Private Function IntToRoman(ByVal number As Integer) As String

        Dim result = New StringBuilder()
        Dim digitsValues = {1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000}
        Dim romanDigits = {"I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M"}
        While number > 0
            For i = digitsValues.Count() - 1 To 0 Step -1
                If (number / digitsValues(i) >= 1) Then
                    number -= digitsValues(i)
                    result.Append(romanDigits(i).ToLower())
                    Exit For
                End If
            Next
        End While
        Return result.ToString()
    End Function

    '' 主要入口点:
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()
        Dim page = doc.NewPage()
        RenderNodes(page, New PointF(Layout.Margin, Layout.Margin), _arthrapods.Children, 0)
        ''
        '' 完毕:
        doc.Save(stream)
        Return doc.Pages.Count
    End Function

    '' 示例树数据:
    Private _arthrapods As New Node("Animalia Arthrapoda") With
        {
            .Children = New List(Of Node) From
            {
                New Node("Insecta") With
                {
                    .Children = New List(Of Node) From
                    {
                        New Node("Archaeognatha") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Protozoa")
                            }
                        },
                        New Node("Thysanura") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Silverfish")
                            }
                        },
                        New Node("Ephemeoptera") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Mafly")
                            }
                        },
                        New Node("Odonata") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Dragonfly"),
                                New Node("Azure Damzelfly"),
                                New Node("Emerald Damzelfly")
                            }
                        },
                        New Node("Orthoptera") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Grasshopper"),
                                New Node("Cricket"),
                                New Node("Cave Cricket")
                            }
                        },
                        New Node("Phasmatodea") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Walking Stick"),
                                New Node("Leaf Bug")
                            }
                        },
                        New Node("Mantodea") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Praying Mantis")
                            }
                        },
                        New Node("Blattoeda") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Cockroach")
                            }
                        },
                        New Node("Isoptera") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Termite")
                            }
                        },
                        New Node("Phithiraptera") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Bird Lice"),
                                New Node("Human Lice"),
                                New Node("Pubic Lice")
                            }
                        },
                        New Node("Hemiptera") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Cicada"),
                                New Node("Pond Skater"),
                                New Node("Tree Hopper"),
                                New Node("Stink Bug"),
                                New Node("Thrip"),
                                New Node("Alderfly")
                            }
                        },
                        New Node("Siphonatera") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Flea")
                            }
                        }
                    }
                },
                New Node("Myriapoda") With
                {
                    .Children = New List(Of Node) From
                    {
                        New Node("Chilopoda") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Centipede")
                            }
                        },
                        New Node("Diplopoda") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Millipede"),
                                New Node("Pitbug")
                            }
                        }
                    }
                },
                New Node("Crustacea") With
                {
                    .Children = New List(Of Node) From
                    {
                        New Node("Branchiopod") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Brine Shrimp"),
                                New Node("Water Flea")
                            }
                        },
                        New Node("Maxillopod") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Cyclopoid"),
                                New Node("Calgid"),
                                New Node("Barnacles")
                            }
                        },
                        New Node("Malacostracan") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Krill"),
                                New Node("Prawn"),
                                New Node("Shrimp"),
                                New Node("Cancrid Crab"),
                                New Node("Fidder Crab"),
                                New Node("Spider Crab"),
                                New Node("Lobster"),
                                New Node("Hermit Crab"),
                                New Node("Cray Fish")
                            }
                        }
                    }
                },
                New Node("Pycnogonida") With
                {
                    .Children = New List(Of Node) From
                    {
                        New Node("Pycnogonida") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Sea Spider")
                            }
                        }
                    }
                },
                New Node("Merostomata") With
                {
                    .Children = New List(Of Node) From
                    {
                        New Node("Merostomata") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Horseshoe Spider")
                            }
                        }
                    }
                },
                New Node("Arachnida") With
                {
                    .Children = New List(Of Node) From
                    {
                        New Node("Scorpiones") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Buthid"),
                                New Node("Imperial Scorpion")
                            }
                        },
                        New Node("Pseudoscorpions") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Neobisiid"),
                                New Node("Cheliferid")
                            }
                        },
                        New Node("Solfigugae") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Wind Scorpion")
                            }
                        },
                        New Node("Acari") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Tick"),
                                New Node("Mite")
                            }
                        },
                        New Node("Araneae") With
                        {
                            .Children = New List(Of Node) From
                            {
                                New Node("Crib Weaver"),
                                New Node("Funnel-web Spider"),
                                New Node("Funnel Weaver"),
                                New Node("Water Spider"),
                                New Node("Jumping Spider"),
                                New Node("Wolf Spider"),
                                New Node("Nursery-web Spider"),
                                New Node("Crab Spider"),
                                New Node("Black Widow"),
                                New Node("Tiger Oriental Tarantula"),
                                New Node("Mexican Red-legged Tarantula")
                            }
                        }
                    }
                }
            }
        }
End Class