LayoutDemos.vb
''
'' This code is part of Document Solutions for Imaging demos.
'' Copyright (c) MESCIUS inc. All rights reserved.
''
Imports System.Drawing
Imports System.IO
Imports System.Numerics
Imports GrapeCity.Documents.Drawing
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Imaging
Imports GrapeCity.Documents.Layout
Imports GrapeCity.Documents.Layout.Composition
Imports GCTEXT = GrapeCity.Documents.Text
Imports GCDRAW = GrapeCity.Documents.Drawing

'' This integrated demo shows how to use helper classes
'' in the GrapeCity.Documents.Layout.Composition namespace
'' to create complex and flexible constraint-based layouts
'' with custom z-order and clipping.
Public Class LayoutDemos
    Private Shared ReadOnly PageColor As Color = Color.FromArgb(39, 41, 43)
    Private Shared ReadOnly BoxColor As Color = Color.FromArgb(230, 230, 230)
    Private Shared ReadOnly CodeColor As Color = Color.FromArgb(132, 211, 232)
    Private Shared ReadOnly RectColor As Color = Color.FromArgb(64, 126, 148)
    Private Shared ReadOnly DescColor As Color = Color.White

    Private Delegate Sub DrawLayoutSample(g As GcGraphics, pageSize As Size)

    Private Shared ReadOnly c_samples As Dictionary(Of String, DrawLayoutSample) = New Dictionary(Of String, DrawLayoutSample) From {
        {"DrawSample1", AddressOf DrawSample1},
        {"DrawSample2", AddressOf DrawSample2},
        {"DrawSample3", AddressOf DrawSample3},
        {"DrawSample4", AddressOf DrawSample4},
        {"DrawSample5", AddressOf DrawSample5},
        {"DrawSample6", AddressOf DrawSample6},
        {"DrawSample7", AddressOf DrawSample7},
        {"DrawSample8", AddressOf DrawSample8}
    }

    Public Function GenerateImage(
        ByVal pixelSize As Size,
        ByVal dpi As Single,
        ByVal opaque As Boolean,
        Optional ByVal sampleParams As String() = Nothing) As GcBitmap

        Dim drawSample As DrawLayoutSample = Nothing
        If Not c_samples.TryGetValue(sampleParams(3), drawSample) Then
            Throw New Exception($"Unknown parameterized sample: {sampleParams(3)}")
        End If

        Dim bmp = New GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi)
        Using g = bmp.CreateGraphics(PageColor)
            drawSample(g, pixelSize)
        End Using
        Return bmp
    End Function

    '' Strings are name, description, info. Rest are arbitrary strings:
    Public Shared Function GetSampleParamsList() As List(Of String())
        Return New List(Of String()) From {
            New String() {"Figures 1-4", "Figures 1-4: horizontal, vertical, alignment constraint and guidelines", Nothing, "DrawSample1"},
            New String() {"Figure 5", "Figure 5: Barrier constraint anchored to two visuals", Nothing, "DrawSample2"},
            New String() {"Figure 6", "Figure 6: Horizontal chain with weighted widths", Nothing, "DrawSample3"},
            New String() {"Figure 7", "Figure 7: Horizontal chain with evenly distributed rectangles and margins", Nothing, "DrawSample4"},
            New String() {"Figure 8", "Figure 8: Horizontal chain with evenly distributed rectangles, no margins", Nothing, "DrawSample5"},
            New String() {"Figure 9", "Figure 9: Weighted horizontal chain without margins", Nothing, "DrawSample6"},
            New String() {"Figure 10", "Figure 10: Horizontal chain with weighted margins and packed rectangles", Nothing, "DrawSample7"},
            New String() {"Text Flow", "Text flow in and around non-rectangular contours", Nothing, "DrawSample8"}
        }
    End Function

    '' Figures 1-4: horizontal, vertical, alignment constraint and guidelines.
    Private Shared Sub DrawSample1(g As GcGraphics, pageSize As Size)
        g.Transform = Matrix3x2.CreateScale(1.4F)

        '' The Surface object can layout Visuals and draw them on the graphics.
        Dim surf = New Surface()

        '' view1

        '' The View object represents a group of Visuals with a transformation matrix.
        Dim view1 = surf.CreateView(250, 150).Translate(50, 40)

        '' Visual is an element with the associated LayoutRect used for its
        '' positioning/ and a delegate that draws its content on the graphics.
        Dim v = view1.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(1, "A horizontal constraint to the parent:",
            "rA.SetLeft(null, AnchorParam.Left, 90);")
        v.LayoutRect.AnchorExact(Nothing)

        v = view1.CreateVisual(AddressOf DrawRect)
        Dim rA = v.LayoutRect
        rA.SetLeft(Nothing, AnchorParam.Left, 90)
        rA.SetWidth(70)
        rA.SetHeight(40)
        rA.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "A"

        Dim r = view1.CreateVisual(AddressOf DrawLineWithLeftArrow).LayoutRect
        r.AnchorTopBottom(rA, 0, 0)
        r.SetLeft(Nothing, AnchorParam.Left)
        r.SetRight(rA, AnchorParam.Left)

        '' view2
        Dim view2 = surf.CreateView(250, 150).Translate(350, 40)
        v = view2.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(2, "An offset horizontal alignment constraint:",
            "rB.SetLeft(rA, AnchorParam.Left, 40);")
        v.LayoutRect.AnchorExact(Nothing)

        v = view2.CreateVisual(AddressOf DrawRect)
        rA = v.LayoutRect
        rA.AnchorTopLeft(Nothing, 15, 70, 110, 60)
        v.Tag = "A"

        v = view2.CreateVisual(AddressOf DrawRect)
        Dim rB = v.LayoutRect
        rB.SetLeft(rA, AnchorParam.Left, 40)
        rB.SetWidth(60)
        rB.SetHeight(35)
        rB.SetTop(rA, AnchorParam.Bottom, 20)
        v.Tag = "B"

        r = view2.CreateVisual(AddressOf DrawVertLineWithLeftArrow).LayoutRect
        r.SetTop(rA, AnchorParam.VerticalCenter)
        r.SetBottom(rB, AnchorParam.VerticalCenter)
        r.SetLeft(rA, AnchorParam.Left)
        r.SetRight(rB, AnchorParam.Left)

        '' view3
        Dim view3 = surf.CreateView(250, 150).Translate(50, 260)
        v = view3.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(3, "Horizontal and vertical constraints:",
            "rB.SetLeft(rA, AnchorParam.Right, 50);" & vbLf &
            "rC.SetTop(rA, AnchorParam.Bottom, 40);")
        v.LayoutRect.AnchorExact(Nothing)

        v = view3.CreateVisual(AddressOf DrawRect)
        rA = v.LayoutRect
        rA.AnchorTopLeft(Nothing, 15, 30, 70, 40)
        v.Tag = "A"

        v = view3.CreateVisual(AddressOf DrawRect)
        rB = v.LayoutRect
        rB.SetLeft(rA, AnchorParam.Right, 50)
        rB.SetWidth(70)
        rB.SetHeight(40)
        rB.SetTop(rA, AnchorParam.Top)
        v.Tag = "B"

        v = view3.CreateVisual(AddressOf DrawRect)
        Dim rC = v.LayoutRect
        rC.SetTop(rA, AnchorParam.Bottom, 40)
        rC.SetWidth(70)
        rC.SetHeight(40)
        rC.SetLeft(rA, AnchorParam.Left)
        v.Tag = "C"

        r = view3.CreateVisual(AddressOf DrawLineWithLeftArrow).LayoutRect
        r.AnchorTopBottom(rA, 0, 0)
        r.SetLeft(rA, AnchorParam.Right)
        r.SetRight(rB, AnchorParam.Left)

        r = view3.CreateVisual(AddressOf DrawLineWithUpArrow).LayoutRect
        r.AnchorLeftRight(rA, 0, 0)
        r.SetTop(rA, AnchorParam.Bottom)
        r.SetBottom(rC, AnchorParam.Top)

        '' view4
        Dim view4 = surf.CreateView(250, 150).Translate(350, 260)
        Dim layoutView = view4.LayoutView
        v = view4.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(4, "A rectangle constrained to a guideline:",
            "var anchorPoint = layoutView.CreatePoint(0.25f, 0);" & vbLf &
            "rA.SetLeft(anchorPoint, 60);")
        v.LayoutRect.AnchorExact(Nothing)

        '' An anchor point can work as the guideline on the X or the Y axes.
        Dim anchorPoint = layoutView.CreatePoint(0.25F, 0)

        v = view4.CreateVisual(AddressOf DrawVertGuideline)
        Dim rG = v.LayoutRect
        rG.SetLeft(anchorPoint)
        rG.AnchorVerticalLine(Nothing)
        v.Tag = "25 %"

        v = view4.CreateVisual(AddressOf DrawRect)
        rA = v.LayoutRect
        rA.SetLeft(anchorPoint, 60)
        rA.SetWidth(70)
        rA.SetHeight(40)
        rA.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "A"

        r = view4.CreateVisual(AddressOf DrawLineWithLeftArrow).LayoutRect
        r.AnchorTopBottom(rA, 0, 0)
        r.SetLeft(rG, AnchorParam.Left)
        r.SetRight(rA, AnchorParam.Left)

        surf.Render(g)
    End Sub

    '' Figure 5: Barrier constraint anchored to two visuals.
    Private Shared Sub DrawSample2(g As GcGraphics, pageSize As Size)
        g.Transform = Matrix3x2.CreateScale(2)

        Dim surf = New Surface()

        '' View1
        Dim view1 = surf.CreateView(350, 160).Translate(30, 30)
        view1.CreateVisual(AddressOf DrawView).LayoutRect.AnchorExact(Nothing)

        Dim v = view1.CreateVisual(AddressOf DrawRect)
        Dim rA = v.LayoutRect
        rA.AnchorTopLeft(Nothing, 30, 50, 60, 40)
        v.Tag = "A"

        v = view1.CreateVisual(AddressOf DrawRect)
        Dim rB = v.LayoutRect
        rB.AnchorTopLeft(Nothing, 90, 50, 90, 40)
        v.Tag = "B"

        v = view1.CreateVisual(AddressOf DrawVertGuideline)
        Dim rG = v.LayoutRect

        '' Adding multiple MinLeft constraints to the same rectangle creates
        '' a barrier to be used as the base for other rectangles.
        rG.AppendMinLeft(rA, AnchorParam.Right)
        rG.AppendMinLeft(rB, AnchorParam.Right)

        rG.AnchorVerticalLine(Nothing)

        v = view1.CreateVisual(AddressOf DrawRect)
        Dim rC = v.LayoutRect
        rC.AppendMinLeft(rA, AnchorParam.Right, 50)
        rC.AppendMinLeft(rB, AnchorParam.Right, 50)
        rC.SetWidth(70)
        rC.SetHeight(40)
        rC.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "C"

        Dim r = view1.CreateVisual(AddressOf DrawLineWithLeftArrow).LayoutRect
        r.AnchorTopBottom(rC, 0, 0)
        r.SetLeft(rG, AnchorParam.Right)
        r.SetRight(rC, AnchorParam.Left)

        '' View2
        Dim view2 = surf.CreateView(350, 160).Translate(30, 210)
        v = view2.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(5, "C is constrained to a barrier, which moves based on" & vbLf &
            "the position and size of both A and B:",
            "rC.AppendMinLeft(rA, AnchorParam.Right, 50);" & vbLf &
            "rC.AppendMinLeft(rB, AnchorParam.Right, 50);")
        v.LayoutRect.AnchorExact(Nothing)

        v = view2.CreateVisual(AddressOf DrawRect)
        rA = v.LayoutRect
        rA.AnchorTopLeft(Nothing, 30, 50, 130, 40)
        v.Tag = "A"

        v = view2.CreateVisual(AddressOf DrawRect)
        rB = v.LayoutRect
        rB.AnchorTopLeft(Nothing, 90, 50, 90, 40)
        v.Tag = "B"

        v = view2.CreateVisual(AddressOf DrawVertGuideline)
        rG = v.LayoutRect
        rG.AppendMinLeft(rA, AnchorParam.Right)
        rG.AppendMinLeft(rB, AnchorParam.Right)
        rG.AnchorVerticalLine(Nothing)

        v = view2.CreateVisual(AddressOf DrawRect)
        rC = v.LayoutRect
        rC.AppendMinLeft(rA, AnchorParam.Right, 50)
        rC.AppendMinLeft(rB, AnchorParam.Right, 50)
        rC.SetWidth(70)
        rC.SetHeight(40)
        rC.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "C"

        r = view2.CreateVisual(AddressOf DrawLineWithLeftArrow).LayoutRect
        r.AnchorTopBottom(rC, 0, 0)
        r.SetLeft(rG, AnchorParam.Right)
        r.SetRight(rC, AnchorParam.Left)

        surf.Render(g)
    End Sub

    '' Figure 6: Horizontal chain with weighted widths.
    Private Shared Sub DrawSample3(g As GcGraphics, pageSize As Size)
        g.Transform = Matrix3x2.CreateScale(2)

        Dim surf = New Surface()

        Dim view = surf.CreateView(350, 120).Translate(30, 40)
        Dim v = view.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(6, "A horizontal chain with two rectangles having weighted" & vbLf & "widths and a fixed space between them:",
            "rA.SetLeft(null, AnchorParam.Left, 60);" & vbLf &
            "rA.SetStarWidth(1);" & vbLf &
            "rAB.SetLeftAndOpposite(rA, AnchorParam.Right);" & vbLf &
            "rAB.SetWidth(50);" & vbLf &
            "rB.SetLeftAndOpposite(rAB, AnchorParam.Right);" & vbLf &
            "rB.SetStarWidth(2);" & vbLf &
            "rB.SetRight(null, AnchorParam.Right, -60);")
        v.LayoutRect.AnchorExact(Nothing)

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rA = v.LayoutRect
        rA.SetHeight(40)
        rA.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "A"

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rB = v.LayoutRect
        rB.SetHeight(40)
        rB.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "B"

        Dim rAB = view.CreateVisual(AddressOf DrawLeftRightLines).LayoutRect
        rAB.AnchorTopBottom(rA, 0, 0)

        '' The SetStarWidth method sets the weight of width of that specific
        '' rectangle relative to the width of other rectangles that belong
        '' to the same chain and have the "star" width.

        '' SetLeftAndOpposite method makes a chain of rectangles that affect
        '' the position of each other in both directions.

        rA.SetLeft(Nothing, AnchorParam.Left, 60)
        rA.SetStarWidth(1)
        rAB.SetLeftAndOpposite(rA, AnchorParam.Right)
        rAB.SetWidth(50)
        rB.SetLeftAndOpposite(rAB, AnchorParam.Right)
        rB.SetStarWidth(2)
        rB.SetRight(Nothing, AnchorParam.Right, -60)

        Dim r = view.CreateVisual(AddressOf DrawLineWithLeftArrow).LayoutRect
        r.AnchorTopBottom(rA, 0, 0)
        r.SetLeft(Nothing, AnchorParam.Left)
        r.SetRight(rA, AnchorParam.Left)

        r = view.CreateVisual(AddressOf DrawLineWithRightArrow).LayoutRect
        r.AnchorTopBottom(rB, 0, 0)
        r.SetLeft(rB, AnchorParam.Right)
        r.SetRight(Nothing, AnchorParam.Right)

        surf.Render(g)
    End Sub

    '' Figure 7: Horizontal chain with evenly distributed rectangles and margins.
    Private Shared Sub DrawSample4(g As GcGraphics, pageSize As Size)
        g.Transform = Matrix3x2.CreateScale(1.8F)

        Dim surf = New Surface()

        Dim view = surf.CreateView(430, 120).Translate(30, 40)
        Dim v = view.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(7, "A horizontal chain with three evenly distributed rectangles" & vbLf & "after margins are accounted for:",
            "rA.SetLeft(null, AnchorParam.Left, 60);" & vbLf &
            "rA.SetWidth(70);" & vbLf &
            "rAB.SetLeftAndOpposite(rA, AnchorParam.Right);" & vbLf &
            "rAB.SetStarWidth(1);" & vbLf &
            "rAB.SetRightAndOpposite(rB, AnchorParam.Left);" & vbLf &
            "rB.SetWidth(70);" & vbLf &
            "rBC.SetLeftAndOpposite(rB, AnchorParam.Right);" & vbLf &
            "rBC.SetStarWidth(1);" & vbLf &
            "rC.SetLeftAndOpposite(rBC, AnchorParam.Right);" & vbLf &
            "rC.SetWidth(70);" & vbLf &
            "rC.SetRight(null, AnchorParam.Right, -60);")
        v.LayoutRect.AnchorExact(Nothing)

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rA = v.LayoutRect
        rA.SetHeight(40)
        rA.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "A"

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rB = v.LayoutRect
        rB.SetHeight(40)
        rB.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "B"

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rC = v.LayoutRect
        rC.SetHeight(40)
        rC.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "C"

        Dim rAB = view.CreateVisual(AddressOf DrawLeftRightLines).LayoutRect
        rAB.AnchorTopBottom(rA, 0, 0)

        Dim rBC = view.CreateVisual(AddressOf DrawLeftRightLines).LayoutRect
        rBC.AnchorTopBottom(rB, 0, 0)

        rA.SetLeft(Nothing, AnchorParam.Left, 60)
        rA.SetWidth(70)
        rAB.SetLeftAndOpposite(rA, AnchorParam.Right)
        rAB.SetStarWidth(1)
        rAB.SetRightAndOpposite(rB, AnchorParam.Left)
        rB.SetWidth(70)
        rBC.SetLeftAndOpposite(rB, AnchorParam.Right)
        rBC.SetStarWidth(1)
        rC.SetLeftAndOpposite(rBC, AnchorParam.Right)
        rC.SetWidth(70)
        rC.SetRight(Nothing, AnchorParam.Right, -60)

        Dim r = view.CreateVisual(AddressOf DrawLineWithLeftArrow).LayoutRect
        r.AnchorTopBottom(rA, 0, 0)
        r.SetLeft(Nothing, AnchorParam.Left)
        r.SetRight(rA, AnchorParam.Left)

        r = view.CreateVisual(AddressOf DrawLineWithRightArrow).LayoutRect
        r.AnchorTopBottom(rC, 0, 0)
        r.SetLeft(rC, AnchorParam.Right)
        r.SetRight(Nothing, AnchorParam.Right)

        surf.Render(g)
    End Sub

    '' Figure 8: Horizontal chain with evenly distributed rectangles, no margins.
    Private Shared Sub DrawSample5(g As GcGraphics, pageSize As Size)
        g.Transform = Matrix3x2.CreateScale(2)

        Dim surf = New Surface()

        Dim view = surf.CreateView(340, 120).Translate(30, 40)
        Dim v = view.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(8, "Same as Figure 7, without accounting for the margins:",
            "rA.SetLeft(null, AnchorParam.Left);" & vbLf &
            "rA.SetWidth(70);" & vbLf &
            "rA.SetRightAndOpposite(rAB, AnchorParam.Left);" & vbLf &
            "rAB.SetStarWidth(1);" & vbLf &
            "rB.SetLeftAndOpposite(rAB, AnchorParam.Right);" & vbLf &
            "rB.SetWidth(70);" & vbLf &
            "rB.SetRightAndOpposite(rBC, AnchorParam.Left);" & vbLf &
            "rBC.SetStarWidth(1);" & vbLf &
            "rC.SetLeftAndOpposite(rBC, AnchorParam.Right);" & vbLf &
            "rC.SetWidth(70);" & vbLf &
            "rC.SetRight(null, AnchorParam.Right);")
        v.LayoutRect.AnchorExact(Nothing)

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rA = v.LayoutRect
        rA.SetHeight(40)
        rA.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "A"

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rB = v.LayoutRect
        rB.SetHeight(40)
        rB.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "B"

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rC = v.LayoutRect
        rC.SetHeight(40)
        rC.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "C"

        Dim rAB = view.CreateVisual(AddressOf DrawLeftRightLines).LayoutRect
        rAB.AnchorTopBottom(rA, 0, 0)

        Dim rBC = view.CreateVisual(AddressOf DrawLeftRightLines).LayoutRect
        rBC.AnchorTopBottom(rB, 0, 0)

        rA.SetLeft(Nothing, AnchorParam.Left)
        rA.SetWidth(70)
        rA.SetRightAndOpposite(rAB, AnchorParam.Left)
        rAB.SetStarWidth(1)
        rB.SetLeftAndOpposite(rAB, AnchorParam.Right)
        rB.SetWidth(70)
        rB.SetRightAndOpposite(rBC, AnchorParam.Left)
        rBC.SetStarWidth(1)
        rC.SetLeftAndOpposite(rBC, AnchorParam.Right)
        rC.SetWidth(70)
        rC.SetRight(Nothing, AnchorParam.Right)

        surf.Render(g)
    End Sub

    '' Figure 9: Weighted horizontal chain without margins.
    Private Shared Sub DrawSample6(g As GcGraphics, pageSize As Size)
        g.Transform = Matrix3x2.CreateScale(2)

        Dim surf = New Surface()

        Dim view = surf.CreateView(340, 120).Translate(30, 40)
        Dim v = view.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(9, "A weighted horizontal chain without margins:",
            "rA.SetLeft(null, AnchorParam.Left);" & vbLf &
            "rA.SetStarWidth(1);" & vbLf &
            "rA.SetRightAndOpposite(rB, AnchorParam.Left);" & vbLf &
            "rB.SetStarWidth(2);" & vbLf &
            "rB.SetRightAndOpposite(rC, AnchorParam.Left);" & vbLf &
            "rC.SetStarWidth(2);" & vbLf &
            "rC.SetRight(null, AnchorParam.Right);")
        v.LayoutRect.AnchorExact(Nothing)

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rA = v.LayoutRect
        rA.SetHeight(40)
        rA.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "A"

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rB = v.LayoutRect
        rB.SetHeight(40)
        rB.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "B"

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rC = v.LayoutRect
        rC.SetHeight(40)
        rC.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "C"

        rA.SetLeft(Nothing, AnchorParam.Left)
        rA.SetStarWidth(1)
        rA.SetRightAndOpposite(rB, AnchorParam.Left)
        rB.SetStarWidth(2)
        rB.SetRightAndOpposite(rC, AnchorParam.Left)
        rC.SetStarWidth(2)
        rC.SetRight(Nothing, AnchorParam.Right)

        surf.Render(g)
    End Sub

    '' Figure 10: Horizontal chain with weighted margins and packed rectangles.
    Private Shared Sub DrawSample7(g As GcGraphics, pageSize As Size)
        g.Transform = Matrix3x2.CreateScale(2)

        Dim surf = New Surface()

        Dim view = surf.CreateView(370, 120).Translate(30, 40)
        Dim v = view.CreateVisual(AddressOf DrawView)
        v.Tag = New FigureCaption(10, "Rectangles are packed together after margins with weights" & vbLf & "are accounted for:",
            "rBeforeA.SetLeft(null, AnchorParam.Left);" & vbLf &
            "rBeforeA.SetStarWidth(3);" & vbLf &
            "rA.SetLeftAndOpposite(rBeforeA, AnchorParam.Right);" & vbLf &
            "rA.SetWidth(70);" & vbLf &
            "rB.SetLeftAndOpposite(rA, AnchorParam.Right);" & vbLf &
            "rB.SetWidth(70);" & vbLf &
            "rC.SetLeftAndOpposite(rB, AnchorParam.Right);" & vbLf &
            "rC.SetWidth(70);" & vbLf &
            "rAfterC.SetLeftAndOpposite(rC, AnchorParam.Right);" & vbLf &
            "rAfterC.SetStarWidth(1);" & vbLf &
            "rAfterC.SetRight(null, AnchorParam.Right);")
        v.LayoutRect.AnchorExact(Nothing)

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rA = v.LayoutRect
        rA.SetHeight(40)
        rA.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "A"

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rB = v.LayoutRect
        rB.SetHeight(40)
        rB.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "B"

        v = view.CreateVisual(AddressOf DrawRect)
        Dim rC = v.LayoutRect
        rC.SetHeight(40)
        rC.SetVerticalCenter(Nothing, AnchorParam.VerticalCenter)
        v.Tag = "C"

        Dim rBeforeA = view.CreateVisual(AddressOf DrawLineWithLeftArrow).LayoutRect
        rBeforeA.AnchorTopBottom(rA, 0, 0)

        Dim rAfterC = view.CreateVisual(AddressOf DrawLineWithRightArrow).LayoutRect
        rAfterC.AnchorTopBottom(rC, 0, 0)

        rBeforeA.SetLeft(Nothing, AnchorParam.Left)
        rBeforeA.SetStarWidth(3)
        rA.SetLeftAndOpposite(rBeforeA, AnchorParam.Right)
        rA.SetWidth(70)
        rB.SetLeftAndOpposite(rA, AnchorParam.Right)
        rB.SetWidth(70)
        rC.SetLeftAndOpposite(rB, AnchorParam.Right)
        rC.SetWidth(70)
        rAfterC.SetLeftAndOpposite(rC, AnchorParam.Right)
        rAfterC.SetStarWidth(1)
        rAfterC.SetRight(Nothing, AnchorParam.Right)

        surf.Render(g)
    End Sub

    '' Text flow in and around non-rectangular contours.
    Private Shared Sub DrawSample8(g As GcGraphics, pageSize As Size)
        g.FillRectangle(New RectangleF(0, 0, pageSize.Width, pageSize.Height), Color.White)

        Dim surf = New Surface()

        '' Contour objects can be referenced in constraints defined for text rectangles.
        Dim c1_outer As Contour = Nothing
        CreateFigure1(surf, c1_outer)
        Dim c2_outer As Contour = Nothing
        Dim c2_inner As Contour = Nothing
        CreateFigure2(surf, c2_outer, c2_inner)

        Const rowHeight As Single = 24F
        Const lineSpacing As Single = 5F
        Const paragraphSpacing As Single = 10F
        Const fontSize As Single = 18F

        '' The main View object that displays horizontal text.
        Dim view = surf.CreateView(pageSize.Width, pageSize.Height)
        Dim rcMargin = view.CreateSpace().LayoutRect
        rcMargin.AnchorDeflate(Nothing, 20)

        Dim tf = New TextFormat() With
            {
                .Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSans.ttf")),
                .FontSizeInGraphicUnits = True,
                .FontSize = fontSize,
                .FontFeatures = New FontFeature() {New FontFeature(FeatureTag.liga, False)}
            }
        Dim noRects = New List(Of ObjectRect)()

        Dim tl As TextLayout = Nothing

        Dim tso = New TextSplitOptions() With
            {
                .RestObjectRects = noRects,
                .AllowMovingAllToRest = True
            }

        Dim rcPrevTop As LayoutRect = Nothing
        Dim rcPrevLeft As LayoutRect = Nothing
        Dim paragraphStarted = False

        While True
            Dim r0 = view.CreateVisual(AddressOf DrawTextFragment).LayoutRect
            If rcPrevLeft IsNot Nothing Then
                r0.SetTop(rcPrevLeft, AnchorParam.Top)
            ElseIf rcPrevTop IsNot Nothing Then
                r0.SetTop(rcPrevTop, AnchorParam.Bottom, If(paragraphStarted, lineSpacing, paragraphSpacing))
            Else
                r0.SetTop(rcMargin, AnchorParam.Top)
            End If
            If rcPrevLeft Is Nothing Then
                r0.SetLeft(rcMargin, AnchorParam.Left)
            Else
                r0.SetLeft(rcPrevLeft, AnchorParam.Right)
            End If

            r0.SetHeight(rowHeight)
            r0.AppendMaxRight(rcMargin, AnchorParam.Right)

            Dim r1 = view.CreateSpace().LayoutRect
            r1.SetTop(r0, AnchorParam.Top)
            r1.SetHeight(rowHeight)
            r1.SetLeft(r0, AnchorParam.Right)
            r1.AppendMaxRight(rcMargin, AnchorParam.Right)

            r0.AppendMaxRight(c1_outer, ContourPosition.FirstInOutside)
            r0.AppendMaxRight(c2_outer, ContourPosition.FirstInOutside)

            r1.AppendMaxRight(c1_outer, ContourPosition.NextOutOutside)
            r1.AppendMaxRight(c2_outer, ContourPosition.NextOutOutside)

            surf.PerformLayout()

            If Not paragraphStarted Then
                '' It is important to have the ObjectRects property set
                '' to a not null value (an empty list works well) and
                '' the AllowOverhangingWords property set to true.

                tl = g.CreateTextLayout()
                tl.ObjectRects = noRects
                tl.TextAlignment = TextAlignment.Justified
                tl.AllowOverhangingWords = True
                tl.FirstLineIndent = 40F
                tl.JustifiedTextExtension = 0.1F

                tl.Append(Util.LoremIpsum(1), tf)

                tl.MaxWidth = r0.Width
                tl.MaxHeight = r0.Height
                CType(r0.Tag, Visual).Tag = tl

                If Not tl.PerformLayout() Then
                    paragraphStarted = True
                End If
            Else
                tso.RestMaxWidth = r0.Width
                tso.RestMaxHeight = r0.Height
                Dim rest As TextLayout = Nothing
                Dim res = tl.Split(tso, rest)
                If res <> SplitResult.CannotSplit Then
                    tl = rest
                    CType(r0.Tag, Visual).Tag = rest
                    If tl.PerformLayout() Then
                        paragraphStarted = False
                    End If
                End If
            End If

            If paragraphStarted AndAlso r1.Width > 0F Then
                rcPrevLeft = r1
            Else
                CType(r1.Tag, Space).Detach()
                Dim spacing = If(paragraphStarted, lineSpacing, paragraphSpacing)
                If rcMargin.P2Y - r0.P2Y < spacing + rowHeight Then
                    Exit While
                End If
                rcPrevLeft = Nothing
                rcPrevTop = r0
            End If
        End While

        tl.Truncate(TrimmingGranularity.Word)

        '' The second View showing text in the ellipse.
        Dim view2 = surf.CreateView(pageSize.Width \ 3, pageSize.Height \ 2).Translate(520, 260).Rotate(15)

        tf = New TextFormat(tf) With
            {
                .ForeColor = Color.Purple,
                .FontSize = 14
            }
        tl = g.CreateTextLayout()
        tl.ObjectRects = noRects
        tl.TextAlignment = TextAlignment.Center
        tl.AllowOverhangingWords = True

        tl.Append(Util.LoremIpsum(1), tf)

        rcPrevTop = Nothing
        paragraphStarted = False

        While True
            Dim r0 = view2.CreateSpace().LayoutRect
            If rcPrevTop IsNot Nothing Then
                r0.SetTop(rcPrevTop, AnchorParam.Bottom, 4)
            Else
                r0.SetTop(Nothing, AnchorParam.Top)
            End If
            r0.SetLeft(Nothing, AnchorParam.Left)

            r0.SetHeight(18)
            r0.AppendMaxRight(Nothing, AnchorParam.Right)

            Dim r1 = view2.CreateVisual(AddressOf DrawTextFragment).LayoutRect
            r1.SetTop(r0, AnchorParam.Top)
            r1.SetHeight(18)
            r1.SetLeft(r0, AnchorParam.Right)
            r1.AppendMaxRight(Nothing, AnchorParam.Right)

            r0.AppendMaxRight(c2_inner, ContourPosition.FirstInInside)
            r1.AppendMaxRight(c2_inner, ContourPosition.NextOutInside)

            surf.PerformLayout()
            If r1.Width = 0F Then
                CType(r1.Tag, Space).Detach()
                If paragraphStarted Then
                    Exit While
                End If
            ElseIf Not paragraphStarted Then
                tl.MaxWidth = r1.Width
                tl.MaxHeight = r1.Height
                CType(r1.Tag, Visual).Tag = tl
                If tl.PerformLayout() Then
                    Exit While
                End If
                paragraphStarted = True
            Else
                tso.RestMaxWidth = r1.Width
                tso.RestMaxHeight = r1.Height
                Dim rest As TextLayout = Nothing
                Dim res = tl.Split(tso, rest)
                If res = SplitResult.FitAll Then
                    CType(r1.Tag, Space).Detach()
                    Exit While
                End If
                If res = SplitResult.Split Then
                    CType(r1.Tag, Visual).Tag = rest
                    tl = rest
                End If
            End If
            rcPrevTop = r0
        End While

        tl.Truncate(TrimmingGranularity.Word)

        surf.Render(g)
    End Sub

    ''
    '' Common utility classes and methods.
    ''

    Private Class FigureCaption
        Public ReadOnly Property Number As Integer
        Public ReadOnly Property Description As String
        Public ReadOnly Property Code As String

        Public Sub New(number As Integer, description As String, Optional code As String = Nothing)
            Me.Number = number
            Me.Description = description
            Me.Code = code
        End Sub
    End Class

    Private Shared Sub DrawTextFragment(g As GcGraphics, v As Visual)
        Dim tl = TryCast(v.Tag, TextLayout)
        If tl IsNot Nothing Then
            g.DrawTextLayout(tl, New PointF(0, 0))
        End If
    End Sub

    Private Shared Sub CreateFigure1(surf As Surface, ByRef c_outer As Contour)
        '' A View for the yellow polygon.
        Dim view = surf.CreateView(0, 0).Translate(120, -40).Rotate(40)
        Dim lv = view.LayoutView

        Dim c = lv.CreateContour()

        Dim v = view.CreateVisual(c, True, Sub(gr As GcGraphics, vis As Visual)
                                                gr.FillPolygon(vis.Points, Color.LemonChiffon)
                                                gr.DrawPolygon(vis.Points, Color.Green, 3)
                                            End Sub)
        Dim rect = v.LayoutRect
        rect.AnchorTopLeft(Nothing, 100, 150, 170, 70)

        c.AddPoints(New AnchorPoint() {
            rect.CreatePoint(0, 0, -20, -20),
            rect.CreatePoint(1, 0, 20, -20),
            rect.CreatePoint(1, 0, 20, -120),
            rect.CreatePoint(1, 0, 120, -120),
            rect.CreatePoint(1, 1, 120, 20),
            rect.CreatePoint(0, 1, -20, 20)
        })

        surf.PerformLayout()

        Dim points = c.MapToView(lv)

        '' To make the outer offset from the Contour we convert
        '' the Contour to a GraphicsPath, then apply the Widen
        '' method with a thick pen. The resulting figure is
        '' used for creating the outer Contour.
        Dim gp = New GraphicsPath(New FreeFormPolygon(points))
        Dim gp2 = gp.Widen(New GCDRAW.Pen(Color.White, 7 * 2))

        Dim fig_outer = gp2.Figures(0)

        fig_outer.Flatten()
        Dim outer_points = fig_outer.TransformedPoints

        c_outer = lv.CreateContour()
        For i = 0 To outer_points.Length - 1
            Dim p = outer_points(i)
            c_outer.AddPoint(lv.CreatePoint(0F, 0F, p.X, p.Y))
        Next
    End Sub

    Private Shared Sub CreateFigure2(surf As Surface, ByRef c_outer As Contour, ByRef c_inner As Contour)
        '' A View for the rotated ellipse.
        Dim view = surf.CreateView(360, 150).Translate(450, 530).Rotate(-40)
        Dim lv = view.LayoutView

        Dim c = lv.CreateContour()

        view.CreateVisual(c, False, Sub(gr As GcGraphics, vis As Visual)
                                         gr.DrawPolygon(vis.Points, Color.DeepPink, 3)
                                     End Sub)

        '' To make the inner and the outer offsets from the ellipse
        '' we convert the elliptic figure to an array of points which
        '' is used later for creating a GraphicsPath. Then, we call
        '' the GraphicsPath.Widen method with a thick pen.
        '' The resulting outer and inner figures can be converted
        '' into new contours for later use in constraints.
        Dim ef As IFigure = New EllipticFigure(lv.AsRectF())
        ef.Flatten()
        Dim points = ef.TransformedPoints
        Dim count = points.Length
        Dim list = New List(Of AnchorPoint)(count)
        For i = 0 To count - 1
            Dim p = points(i)
            list.Add(lv.CreatePoint(0, 0, p.X, p.Y))
        Next
        c.AddPoints(list)

        Dim gp = New GraphicsPath(ef)
        Dim gp2 = gp.Widen(New GCDRAW.Pen(Color.White, 7 * 2))

        Dim fig_outer = gp2.Figures(0)
        Dim fig_inner = gp2.Figures(1)

        fig_outer.Flatten()
        Dim outer_points = fig_outer.TransformedPoints

        c_outer = lv.CreateContour()
        For i = 0 To outer_points.Length - 1
            Dim p = outer_points(i)
            c_outer.AddPoint(lv.CreatePoint(0F, 0F, p.X, p.Y))
        Next

        fig_inner.Flatten()
        Dim inner_points = fig_inner.TransformedPoints

        c_inner = lv.CreateContour()
        For i = 0 To inner_points.Length - 1
            Dim p = inner_points(i)
            c_inner.AddPoint(lv.CreatePoint(0F, 0F, p.X, p.Y))
        Next
    End Sub

    Private Shared ReadOnly FormatBox As TextFormat = New TextFormat() With
        {
            .Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeSans.ttf")),
            .FontSize = 14,
            .FontSizeInGraphicUnits = True,
            .ForeColor = BoxColor
        }

    Private Shared ReadOnly FormatDesc As TextFormat = New TextFormat(FormatBox) With
        {
            .FontSize = 12,
            .ForeColor = DescColor
        }

    Private Shared ReadOnly FormatCaption As TextFormat = New TextFormat(FormatDesc) With
        {
            .FontBold = True
        }

    Private Shared ReadOnly FormatCode As TextFormat = New TextFormat(FormatDesc) With
        {
            .Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "FreeMono.ttf")),
            .ForeColor = CodeColor
        }

    Private Shared Sub DrawView(g As GcGraphics, v As Visual)
        Dim rect = v.AsRectF()
        g.FillRectangle(rect, Color.FromArgb(31, 82, 100))
        g.DrawRectangle(rect, New GCDRAW.Pen(Color.FromArgb(200, 200, 200), 1) With
            {
                .DashPattern = New Single() {7, 3}
            })
        Dim fc = TryCast(v.Tag, FigureCaption)
        If fc IsNot Nothing Then
            Dim tl = g.CreateTextLayout()
            tl.Append($"Figure {fc.Number}. ", FormatCaption)
            tl.AppendLine(fc.Description, FormatDesc)
            If fc.Code IsNot Nothing Then
                tl.Append(fc.Code, FormatCode)
            End If
            g.DrawTextLayout(tl, New PointF(0, v.Height + 5))
        End If
    End Sub

    Private Shared Sub DrawVertGuideline(g As GcGraphics, v As Visual)
        g.DrawLine(New PointF(0, 0), New PointF(0, v.Height), New GCDRAW.Pen(BoxColor, 1) With
            {
                .DashPattern = New Single() {1, 2}
            })
        Dim s = TryCast(v.Tag, String)
        If s IsNot Nothing Then
            Dim tl = g.CreateTextLayout()
            tl.Append(s, FormatDesc)
            tl.PerformLayout()
            Dim rect = tl.ContentRectangle
            rect.X = -rect.Width * 0.5F
            rect.Y = 10
            rect.Inflate(3, 1)
            g.FillRoundRect(rect, 3, RectColor)
            g.DrawTextLayout(tl, New PointF(rect.X + 3, rect.Y + 1))
        End If
    End Sub

    Private Shared Sub DrawRect(g As GcGraphics, v As Visual)
        Dim rect = v.AsRectF()
        g.FillRectangle(rect, RectColor)
        g.DrawRectangle(rect, New GCDRAW.Pen(BoxColor, 1))
        Dim s = TryCast(v.Tag, String)
        If s IsNot Nothing Then
            Dim tl = g.CreateTextLayout()
            tl.MaxWidth = v.Width
            tl.MaxHeight = v.Height
            tl.TextAlignment = TextAlignment.Center
            tl.ParagraphAlignment = ParagraphAlignment.Center
            tl.Append(s, FormatBox)
            g.DrawTextLayout(tl, New PointF(0, 0))
        End If
    End Sub

    Private Shared Sub DrawLineWithLeftArrow(g As GcGraphics, v As Visual)
        Dim y = v.Height * 0.5F
        g.DrawLine(New PointF(5, y), New PointF(v.Width, y), New GCDRAW.Pen(BoxColor, 0.7F))
        DrawLeftArrow(g, 0, y)
    End Sub

    Private Shared Sub DrawLineWithRightArrow(g As GcGraphics, v As Visual)
        Dim y = v.Height * 0.5F
        g.DrawLine(New PointF(0, y), New PointF(v.Width - 5, y), New GCDRAW.Pen(BoxColor, 0.7F))
        DrawRightArrow(g, v.Width, y)
    End Sub

    Private Shared Sub DrawLeftRightLines(g As GcGraphics, v As Visual)
        Dim y = v.Height * 0.33F
        g.DrawLine(New PointF(5, y), New PointF(v.Width, y), New GCDRAW.Pen(BoxColor, 0.7F))
        DrawLeftArrow(g, 0, y)
        y = v.Height * 0.66F
        g.DrawLine(New PointF(0, y), New PointF(v.Width - 5, y), New GCDRAW.Pen(BoxColor, 0.7F))
        DrawRightArrow(g, v.Width, y)
    End Sub

    Private Shared Sub DrawVertLineWithLeftArrow(g As GcGraphics, v As Visual)
        Dim x = v.Width * 0.5F
        g.DrawLines(New PointF() {
            New PointF(5, 0),
            New PointF(x, 0),
            New PointF(x, v.Height),
            New PointF(v.Width, v.Height)
        }, New GCDRAW.Pen(BoxColor, 0.7F))
        DrawLeftArrow(g, 0, 0)
    End Sub

    Private Shared Sub DrawLineWithUpArrow(g As GcGraphics, v As Visual)
        Dim x = v.Width * 0.5F
        g.DrawLine(New PointF(x, 5), New PointF(x, v.Height), New GCDRAW.Pen(BoxColor, 0.7F))
        DrawUpArrow(g, x, 0)
    End Sub

    Private Shared Sub DrawLeftArrow(g As GcGraphics, x As Single, y As Single)
        Dim pts = New PointF() {
            New PointF(x, y),
            New PointF(x + 8, y - 2.5F),
            New PointF(x + 8, y + 2.5F)
        }
        g.FillPolygon(pts, BoxColor)
    End Sub

    Private Shared Sub DrawRightArrow(g As GcGraphics, x As Single, y As Single)
        Dim pts = New PointF() {
            New PointF(x, y),
            New PointF(x - 8, y + 2.5F),
            New PointF(x - 8, y - 2.5F)
        }
        g.FillPolygon(pts, BoxColor)
    End Sub

    Private Shared Sub DrawUpArrow(g As GcGraphics, x As Single, y As Single)
        Dim pts = New PointF() {
            New PointF(x, y),
            New PointF(x + 2.5F, y + 8),
            New PointF(x - 2.5F, y + 8)
        }
        g.FillPolygon(pts, BoxColor)
    End Sub
End Class