'---------------------------------------------------------------------------------------
' Copyright (c) 2001-2025 by Apryse Software Inc. All Rights Reserved.
' Consult legal.txt regarding legal and license information.
'---------------------------------------------------------------------------------------

Imports System
Imports System.Collections.Generic
Imports pdftron
Imports pdftron.Common
Imports pdftron.SDF
Imports pdftron.PDF
Imports pdftron.PDF.Annots

'---------------------------------------------------------------------------------------
' This sample illustrates basic PDFNet capabilities related to interactive 
' forms (also known as AcroForms). 
'---------------------------------------------------------------------------------------
Module InteractiveFormsTestVB
    Dim pdfNetLoader As PDFNetLoader
    Sub New()
        pdfNetLoader = pdftron.PDFNetLoader.Instance()
    End Sub

    Sub Main()

        PDFNet.Initialize(PDFTronLicense.Key)

        ' Relative path to the folder containing test files.
        ' Dim input_path As String = "../../../../TestFiles/"
        Dim output_path As String = "../../../../TestFiles/Output/"

        ' The vector used to store the name And count of all fields.
        ' This Is used later on to clone the fields
        Dim field_names As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)()

        Try
            '----------------------------------------------------------------------------------
            ' Example 1: Programatically create new Form Fields and Widget Annotations.
            '----------------------------------------------------------------------------------
            Using doc As PDFDoc = New PDFDoc
                ' Create a blank page and some new fields (aka "AcroForms").
                Dim blank_page As Page = doc.PageCreate()

                ' Text Widget Creation 
                ' Create an empty text widget with black text.
                Dim text1 As TextWidget = TextWidget.Create(doc, New Rect(110, 700, 380, 730))
                text1.SetText("Basic Text Field")
                text1.RefreshAppearance()
                blank_page.AnnotPushBack(text1)
                ' Create a vertical text widget with blue text And a yellow background.
                Dim text2 As TextWidget = TextWidget.Create(doc, New Rect(50, 400, 90, 730))
                text2.SetRotation(90)
                ' Set the text content.
                text2.SetText("    ****Lucky Stars!****")
                ' Set the font type, text color, font size, border color And background color.
                text2.SetFont(Font.Create(doc, Font.StandardType1Font.e_helvetica_oblique))
                text2.SetFontSize(28)
                text2.SetTextColor(New ColorPt(0, 0, 1), 3)
                text2.SetBorderColor(New ColorPt(0, 0, 0), 3)
                text2.SetBackgroundColor(New ColorPt(1, 1, 0), 3)
                text2.RefreshAppearance()
                ' Add the annotation to the page.
                blank_page.AnnotPushBack(text2)
                ' Create two New text widget with Field names employee.name.first And employee.name.last
                ' This logic shows how these widgets can be created using either a field name string Or
                ' a Field object
                Dim text3 As TextWidget = TextWidget.Create(doc, New Rect(110, 660, 380, 690), "employee.name.first")
                text3.SetText("Levi")
                text3.SetFont(Font.Create(doc, Font.StandardType1Font.e_times_bold))
                text3.RefreshAppearance()
                blank_page.AnnotPushBack(text3)
                Dim emp_last_name As Field = doc.FieldCreate("employee.name.last", Field.Type.e_text, "Ackerman")
                Dim text4 As TextWidget = TextWidget.Create(doc, New Rect(110, 620, 380, 650), emp_last_name)
                text4.SetFont(Font.Create(doc, Font.StandardType1Font.e_times_bold))
                text4.RefreshAppearance()
                blank_page.AnnotPushBack(text4)

                ' Signature Widget Creation (unsigned)
                Dim signature1 As SignatureWidget = SignatureWidget.Create(doc, New Rect(110, 560, 260, 610))
                signature1.RefreshAppearance()
                blank_page.AnnotPushBack(signature1)

                ' CheckBox Widget Creation
                ' Create a check box widget that Is Not checked.
                Dim check1 As CheckBoxWidget = CheckBoxWidget.Create(doc, New Rect(140, 490, 170, 520))
                check1.RefreshAppearance()
                blank_page.AnnotPushBack(check1)
                ' Create a check box widget that Is checked.
                Dim check2 As CheckBoxWidget = CheckBoxWidget.Create(doc, New Rect(190, 490, 250, 540), "employee.name.check1")
                check2.SetBackgroundColor(New ColorPt(1, 1, 1), 3)
                check2.SetBorderColor(New ColorPt(0, 0, 0), 3)
                ' Check the widget (by default it Is unchecked).
                check2.SetChecked(True)
                check2.RefreshAppearance()
                blank_page.AnnotPushBack(check2)

                ' PushButton Widget Creation
                Dim pushbutton1 As PushButtonWidget = PushButtonWidget.Create(doc, New Rect(380, 490, 520, 540))
                pushbutton1.SetTextColor(New ColorPt(1, 1, 1), 3)
                pushbutton1.SetFontSize(36)
                pushbutton1.SetBackgroundColor(New ColorPt(0, 0, 0), 3)
                ' Add a caption for the pushbutton.
                pushbutton1.SetStaticCaptionText("PushButton")
                pushbutton1.RefreshAppearance()
                blank_page.AnnotPushBack(pushbutton1)

                ' ComboBox Widget Creation
                Dim combo1 As ComboBoxWidget = ComboBoxWidget.Create(doc, New Rect(280, 560, 580, 610))
                ' Add options to the combobox widget.
                combo1.AddOption("Combo Box No.1")
                combo1.AddOption("Combo Box No.2")
                combo1.AddOption("Combo Box No.3")
                ' Make one of the options in the combo box selected by default.
                combo1.SetSelectedOption("Combo Box No.2")
                combo1.SetTextColor(New ColorPt(1, 0, 0), 3)
                combo1.SetFontSize(28)
                combo1.RefreshAppearance()
                blank_page.AnnotPushBack(combo1)

                ' ListBox Widget Creation
                Dim list1 As ListBoxWidget = ListBoxWidget.Create(doc, New Rect(400, 620, 580, 730))
                ' Add one option to the listbox widget.
                list1.AddOption("List Box No.1")
                ' Add multiple options to the listbox widget in a batch.
                Dim list_options As String() = New String(1) {"List Box No.2", "List Box No.3"}
                list1.AddOptions(list_options)
                ' Select some of the options in list box as default options.
                list1.SetSelectedOptions(list_options)
                ' Enable list box to have multi-select when editing.
                list1.GetField().SetFlag(Field.Flag.e_multiselect, True)
                list1.SetFont(Font.Create(doc, Font.StandardType1Font.e_times_italic))
                list1.SetTextColor(New ColorPt(1, 0, 0), 3)
                list1.SetFontSize(28)
                list1.SetBackgroundColor(New ColorPt(1, 1, 1), 3)
                list1.RefreshAppearance()
                blank_page.AnnotPushBack(list1)

                ' RadioButton Widget Creation
                ' Create a radio button group And add three radio buttons in it. 
                Dim radio_group As RadioButtonGroup = RadioButtonGroup.Create(doc, "RadioGroup")
                Dim radiobutton1 As RadioButtonWidget = radio_group.Add(New Rect(140, 410, 190, 460))
                radiobutton1.SetBackgroundColor(New ColorPt(1, 1, 0), 3)
                radiobutton1.RefreshAppearance()
                Dim radiobutton2 As RadioButtonWidget = radio_group.Add(New Rect(310, 410, 360, 460))
                radiobutton2.SetBackgroundColor(New ColorPt(0, 1, 0), 3)
                radiobutton2.RefreshAppearance()
                Dim radiobutton3 As RadioButtonWidget = radio_group.Add(New Rect(480, 410, 530, 460))
                ' Enable the third radio button. By default the first one is selected.
                radiobutton3.EnableButton()
                radiobutton3.SetBackgroundColor(New ColorPt(0, 1, 1), 3)
                radiobutton3.RefreshAppearance()
                radio_group.AddGroupButtonsToPage(blank_page)

                ' Custom push button annotation creation
                Dim custom_pushbutton1 As PushButtonWidget = PushButtonWidget.Create(doc, New Rect(260, 320, 360, 360))
                ' Set the annotation appearance.
                custom_pushbutton1.SetAppearance(CreateCustomButtonAppearance(doc, False), Annot.AnnotationState.e_normal)
                ' Create 'SubmitForm' action. The action will be linked to the button.
                Dim url As FileSpec = FileSpec.CreateURL(doc, "http://www.pdftron.com")
                Dim button_action As pdftron.PDF.Action = pdftron.PDF.Action.CreateSubmitForm(url)
                ' Associate the above action with 'Down' event in annotations action dictionary.
                Dim annot_action As Obj = custom_pushbutton1.GetSDFObj().PutDict("AA")
                annot_action.Put("D", button_action.GetSDFObj())
                blank_page.AnnotPushBack(custom_pushbutton1)

                ' Add the page as the last page in the document.
                doc.PagePushBack(blank_page)

                ' If you are not satisfied with the look of default auto-generated appearance 
                ' streams you can delete "AP" entry from the Widget annotation and set 
                ' "NeedAppearances" flag in AcroForm dictionary:
                '    doc.GetAcroForm().PutBool("NeedAppearances", true)
                '    			
                ' This will force the viewer application to auto-generate new appearance streams 
                ' every time the document is opened.
                '
                ' Alternatively you can generate custom annotation appearance using ElementWriter 
                ' and then set the "AP" entry in the widget dictionary to the new appearance
                ' stream.
                '
                ' Yet another option is to pre-populate field entries with dummy text. When 
                ' you edit the field values using PDFNet the new field appearances will match 
                ' the old ones.
                doc.RefreshFieldAppearances()

                doc.Save(output_path + "forms_test1.pdf", 0)
            End Using
            Console.WriteLine("Done.")

            '----------------------------------------------------------------------------------
            ' Example 2: 
            ' Fill-in forms / Modify values of existing fields.
            ' Traverse all form fields in the document (and print out their names). 
            ' Search for specific fields in the document.
            '----------------------------------------------------------------------------------
            Using doc As PDFDoc = New PDFDoc(output_path & "forms_test1.pdf")
                doc.InitSecurityHandler()
                Dim itr As FieldIterator
                itr = doc.GetFieldIterator()

                While itr.HasNext()
                    Dim field As Field = itr.Current()
                    Dim cur_field_name As String = field.GetName()
                    ' Add one to the count for this field name for later processing
                    field_names(cur_field_name) = (If(field_names.ContainsKey(cur_field_name), field_names(cur_field_name) + 1, 1))
                    Console.WriteLine("Field name: {0}", field.GetName())
                    Console.WriteLine("Field partial name: {0}", field.GetPartialName())
                    Dim str_val As String = field.GetValueAsString()
                    Console.Write("Field type: ")
                    Dim type As Field.Type = field.[GetType]()

                    Select Case type
                        Case Field.Type.e_button
                            Console.WriteLine("Button")
                        Case Field.Type.e_radio
                            Console.WriteLine("Radio button: Value = " & str_val)
                        Case Field.Type.e_check
                            field.SetValue(True)
                            Console.WriteLine("Check box: Value = " & str_val)
                        Case Field.Type.e_text
                            Console.WriteLine("Text")
                            Dim old_value As String = "none"
                            If field.GetValue() IsNot Nothing Then old_value = field.GetValue().GetAsPDFText()
                            ' Edit all variable text in the document
                            field.SetValue("This is a new value. The old one was: " & old_value)
                        Case Field.Type.e_choice
                            Console.WriteLine("Choice")
                        Case Field.Type.e_signature
                            Console.WriteLine("Signature")
                    End Select

                    Console.WriteLine("------------------------------")
                    itr.[Next]()
                End While

                ' Search for a specific field
                Dim fld As Field = doc.GetField("employee.name.first")

                If fld IsNot Nothing Then
                    Console.WriteLine("Field search for {0} was successful", fld.GetName())
                Else
                    Console.WriteLine("Field search failed.")
                End If

                ' Regenerate field appearances.
                doc.RefreshFieldAppearances()
                doc.Save(output_path & "forms_test_edit.pdf", 0)
                ' output PDF doc
                Console.WriteLine("Done.")
            End Using

        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try
        '----------------------------------------------------------------------------------
        ' Sample: Form templating
        ' Replicate pages and form data within a document. Then rename field names to make 
        ' them unique.
        '----------------------------------------------------------------------------------
        Try
            ' Sample: Copying the page with forms within the same document
            Using doc As PDFDoc = New PDFDoc(output_path & "forms_test1.pdf")
                doc.InitSecurityHandler()
                Dim src_page As Page = doc.GetPage(1)
                doc.PagePushBack(src_page)   ' Append several copies of the first page
                doc.PagePushBack(src_page)   ' Note that forms are successfully copied
                doc.PagePushBack(src_page)
                doc.PagePushBack(src_page)

                ' Now we rename fields in order to make every field unique.
                ' You can use this technique for dynamic template filling where you have a 'master'
                ' form page that should be replicated, but with unique field names on every page.
                For Each cur_field As KeyValuePair(Of String, Integer) In field_names
                    RenameAllFields(doc, cur_field.Key, cur_field.Value)
                Next

                doc.Save(output_path & "forms_test1_cloned.pdf", 0)
                ' output PDF doc
                Console.WriteLine("Done.")
            End Using

        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try

        '----------------------------------------------------------------------------------
        ' Sample: 
        ' Flatten all form fields in a document.
        ' Note that this sample is intended to show that it is possible to flatten
        ' individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
        ' that will automatically flatten all fields.
        '----------------------------------------------------------------------------------
        Try

            Using doc As PDFDoc = New PDFDoc(output_path & "forms_test1.pdf")
                doc.InitSecurityHandler()

                ' Traverse all pages
                Dim auto As Boolean = True

                If auto Then
                    doc.FlattenAnnotations()
                Else ' Manual flattening
                    Dim pitr As PageIterator = doc.GetPageIterator()

                    While pitr.HasNext()
                        Dim page As Page = pitr.Current()

                        For i As Integer = page.GetNumAnnots() - 1 To 0
                            Dim annot As Annot = page.GetAnnot(i)

                            If annot.[GetType]() = Annot.Type.e_Widget Then
                                annot.Flatten(page)
                            End If
                        Next

                        pitr.[Next]()
                    End While
                End If

                doc.Save(output_path & "forms_test1_flattened.pdf", 0)
                ' output PDF doc
                Console.WriteLine("Done.")
            End Using

        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try
        PDFNet.Terminate()
    End Sub

    ' field_nums has to be greater than 0.
    Sub RenameAllFields(ByVal doc As PDFDoc, ByVal name As String, ByVal Optional field_nums As Integer = 1)
        Dim fld As Field = doc.GetField(name)
        Dim counter As Integer = 1

        While fld IsNot Nothing
            Dim field_new_name As String = name
            Dim update_count As Integer = System.Convert.ToInt32(Math.Ceiling(counter / CDbl(field_nums)))
            fld.Rename(name & "-" & update_count.ToString())
            fld = doc.GetField(name)
            counter += 1
        End While
    End Sub

    Function CreateCustomButtonAppearance(ByRef doc As PDFDoc, ByVal button_down As Boolean) As Obj
        ' Create a button appearance stream ------------------------------------
        Dim builder As ElementBuilder = New ElementBuilder
        Dim writer As ElementWriter = New ElementWriter

        writer.Begin(doc.GetSDFDoc())

        ' Draw background
        Dim element As Element = builder.CreateRect(0, 0, 101, 37)
        element.SetPathFill(True)
        element.SetPathStroke(False)
        element.GetGState().SetFillColorSpace(ColorSpace.CreateDeviceGray())
        element.GetGState().SetFillColor(New ColorPt(0.75, 0, 0))
        writer.WriteElement(element)

        ' Draw 'Submit' text
        writer.WriteElement(builder.CreateTextBegin())

        element = builder.CreateTextRun("Submit", Font.Create(doc, Font.StandardType1Font.e_helvetica_bold), 12)
        element.GetGState().SetFillColor(New ColorPt(0, 0, 0))

        If (button_down) Then
            element.SetTextMatrix(1, 0, 0, 1, 33, 10)
        Else
            element.SetTextMatrix(1, 0, 0, 1, 30, 13)
        End If

        writer.WriteElement(element)
        writer.WriteElement(builder.CreateTextEnd())

        Dim stm As Obj = writer.End()

        ' Calling Dispose() on ElementReader/Writer/Builder can result in increased performance and lower memory consumption.
        writer.Dispose()
        builder.Dispose()

        ' Set the bounding box
        stm.PutRect("BBox", 0, 0, 101, 37)
        stm.PutName("Subtype", "Form")
        Return stm
    End Function

End Module
