NumberedList2.vb
''
'' This code is part of GrapeCity Documents for PDF samples.
'' Copyright (c) GrapeCity, Inc. All rights reserved.
''
Imports System.IO
Imports System.Drawing
Imports System.Text
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Drawing

'' Demonstrates how different styles of numbered lists can be rendered in GcPdf.
'' See also NumberedList.
Public Class NumberedList2
    '' Encapsulate page layout constants used in the sample:
    Private Structure Layout
        '' All around page margins:
        Public Shared Margin As Single = 72.0F
        '' List offset relative to item number:
        Public Shared ListOffset As Single = 24.0F
        '' List level indent:
        Public Shared ListIndent As Single = 30.0F
    End Structure

    '' Define simple tree type:
    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

    '' Renders a list of nodes as a numbered list.
    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 = New TextLayout()
        tlBullet.DefaultFormat.Font = StandardFonts.Times
        tlBullet.MarginLeft = Layout.ListIndent * level

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

        For i = 0 To nodes.Count - 1
            Dim g = page.Graphics
            '' Prep item text:
            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
            '' Prep item number:
            tlBullet.Clear()
            tlBullet.Append(ItemIdxToString(i, level, tlBullet))
            tlBullet.PerformLayout(True)
            '' Render item:
            g.DrawTextLayout(tlBullet, pt)
            g.DrawTextLayout(tlText, pt)
            '' Advance insertion point:
            pt.Y += tlText.ContentHeight
            '' Render children:
            If nodes(i).Children.Count > 0 Then
                pt = RenderNodes(page, pt, nodes(i).Children, level + 1)
            End If
        Next
        Return pt
    End Function

    '' Convert item index to item number representation, in a
    '' Arabic -> Latin letters -> Roman numbers loop.
    '' Roman numbers are right-aligned, others are left-aligned.
    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

    '' From 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

    '' Main entry point:
    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)
        ''
        '' Done:
        doc.Save(stream)
        Return doc.Pages.Count
    End Function

    '' Sample tree data:
    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