TimeSheetForm.vb
'' '' This code is part of Document Solutions for PDF demos . '' Copyright (c) MESCIUS inc. All rights reserved. '' Imports System . IO Imports System . Drawing Imports GrapeCity . Documents . Pdf Imports GrapeCity . Documents . Pdf . AcroForms Imports GrapeCity . Documents . Text Imports GrapeCity . Documents . Common Imports GrapeCity . Documents . Drawing Imports GCTEXT = GrapeCity . Documents . Text Imports GCDRAW = GrapeCity . Documents . Drawing '' This sample generates a PDF AcroForm representing a time sheet. '' The same code Is used to generated the time sheet in the TimeSheet use case sample. Public Class TimeSheetForm '' Font collection to hold the fonts we need: Private _fc As FontCollection = New FontCollection () '' The text layout used to render input fields when flattening the document: Private _inputTl As TextLayout = New TextLayout ( 72 ) '' The text format used for input fields: Private _inputFont As GCTEXT . Font = FontCollection . SystemFonts . FindFamilyName ( "Segoe UI" , True ) Private _inputFontSize As Single = 12 '' Input fields margin: Private _inputMargin As Single = 5 '' Space for employee's signature: Private _empSignRect As RectangleF '' Logo (we should dispose it after saving the document): Private _logo As GCDRAW . Image '' Main entry point of this sample: Function CreatePDF ( ByVal stream As Stream ) As Integer '' Set up a font collection with the fonts we need: _fc . RegisterDirectory ( Path . Combine ( "Resources" , "Fonts" )) '' Set that font collection on input fields' text layout '' (we will also set it on all text layouts that we'll use): _inputTl . FontCollection = _fc '' Set up layout And formatting for input fields: _inputTl . ParagraphAlignment = ParagraphAlignment . Center '' Create the time sheet input form '' (in a real-life scenario, we probably would only create it once, '' And then re-use the form PDF): Dim doc = MakeTimeSheetForm () '' Save the PDF: doc . Save ( stream ) '' Images used in a document can be disposed only after saving the PDF: _logo . Dispose () '' Done: Return doc . Pages . Count End Function '' Data field names: Private Structure _Names Shared ReadOnly Dows As String () = { "Sun" , "Mon" , "Tue" , "Wed" , "Thu" , "Fri" , "Sat" } Const EmpName = "empName" Const EmpTitle = "empTitle" Const EmpNum = "empNum" Const EmpStatus = "empStatus" Const EmpDep = "empDep" Const EmpSuper = "empSuper" Shared ReadOnly DtNames = New Dictionary ( Of String , String ()) From { { "Sun" , New String () { "dtSun" , "tSunStart" , "tSunEnd" , "tSunReg" , "tSunOvr" , "tSunTotal" }}, { "Mon" , New String () { "dtMon" , "tMonStart" , "tMonEnd" , "tMonReg" , "tMonOvr" , "tMonTotal" }}, { "Tue" , New String () { "dtTue" , "tTueStart" , "tTueEnd" , "tTueReg" , "tTueOvr" , "tTueTotal" }}, { "Wed" , New String () { "dtWed" , "tWedStart" , "tWedEnd" , "tWedReg" , "tWedOvr" , "tWedTotal" }}, { "Thu" , New String () { "dtThu" , "tThuStart" , "tThuEnd" , "tThuReg" , "tThuOvr" , "tThuTotal" }}, { "Fri" , New String () { "dtFri" , "tFriStart" , "tFriEnd" , "tFriReg" , "tFriOvr" , "tFriTotal" }}, { "Sat" , New String () { "dtSat" , "tSatStart" , "tSatEnd" , "tSatReg" , "tSatOvr" , "tSatTotal" }} } Const TotalReg = "totReg" Const TotalOvr = "totOvr" Const TotalHours = "totHours" Const EmpSign = "empSign" Const EmpSignDate = "empSignDate" Const SupSign = "supSign" Const SupSignDate = "supSignDate" End Structure '' Creates the Time Sheet form: Private Function MakeTimeSheetForm () As GcPdfDocument Const marginH = 72.0F , marginV = 48.0F Dim doc = New GcPdfDocument () Dim page = doc . NewPage () Dim g = page . Graphics Dim ip = New PointF ( marginH , marginV ) Dim tl = New TextLayout ( g . Resolution ) With {. FontCollection = _fc } tl . Append ( "TIME SHEET" , New TextFormat () With {. FontName = "Segoe UI" , . FontSize = 18 }) tl . PerformLayout ( True ) g . DrawTextLayout ( tl , ip ) ip . Y += tl . ContentHeight + 15 _logo = GCDRAW . Image . FromFile ( Path . Combine ( "Resources" , "ImagesBis" , "AcmeLogo-vertical-250px.png" )) Dim s = New SizeF ( 250.0F * 0.75F , 64.0F * 0.75F ) g . DrawImage ( _logo , New RectangleF ( ip , s ), Nothing , ImageAlign . Default ) ip . Y += s . Height + 5 tl . Clear () tl . Append ( "Where Business meets Technology" , New TextFormat () With {. FontName = "Segoe UI" , . FontItalic = True , . FontSize = 10 }) tl . PerformLayout ( True ) g . DrawTextLayout ( tl , ip ) ip . Y += tl . ContentHeight + 15 tl . Clear () tl . Append ($ "1901, Halford Avenue,{vbCrLf}Santa Clara, California – 95051-2553,{vbCrLf}United States" , New TextFormat () With {. FontName = "Segoe UI" , . FontSize = 9 }) tl . MaxWidth = page . Size . Width - marginH * 2 tl . TextAlignment = TextAlignment . Trailing tl . PerformLayout ( True ) g . DrawTextLayout ( tl , ip ) ip . Y += tl . ContentHeight + 25 Dim pen = New GCDRAW . Pen ( Color . Gray , 0.5F ) Dim colw = ( page . Size . Width - marginH * 2 ) / 2 Dim fields1 = DrawTable ( ip , New Single () { colw , colw }, New Single () { 30 , 30 , 30 }, g , pen ) Dim tf = New TextFormat () With {. FontName = "Segoe UI" , . FontSize = 9 } With tl . ParagraphAlignment = ParagraphAlignment . Center . TextAlignment = TextAlignment . Leading . MarginLeft = 4 . MarginRight = 4 . MarginTop = 4 . MarginBottom = 4 End With '' t_ - caption '' b_ - bounds '' f_ - field name, null means no field Dim drawField As Action ( Of String , RectangleF , String ) = Sub ( t_ , b_ , f_ ) Dim tWidth As Single If Not String . IsNullOrEmpty ( t_ ) Then tl . Clear () tl . MaxHeight = b_ . Height tl . MaxWidth = b_ . Width tl . Append ( t_ , tf ) tl . PerformLayout ( True ) g . DrawTextLayout ( tl , b_ . Location ) tWidth = tl . ContentRectangle . Right Else tWidth = 0 End If If Not String . IsNullOrEmpty ( f_ ) Then Dim fld = New TextField () With {. Name = f_ } fld . Widget . Page = page fld . Widget . Rect = New RectangleF ( b_ . X + tWidth + _inputMargin , b_ . Y + _inputMargin , b_ . Width - tWidth - _inputMargin * 2 , b_ . Height - _inputMargin * 2 ) fld . Widget . DefaultAppearance . Font = _inputFont fld . Widget . DefaultAppearance . FontSize = _inputFontSize fld . Widget . Border . Color = Color . LightSlateGray fld . Widget . Border . Width = 0.5F doc . AcroForm . Fields . Add ( fld ) End If End Sub drawField ( "EMPLOYEE NAME: " , fields1 ( 0 , 0 ), _Names . EmpName ) drawField ( "TITLE: " , fields1 ( 1 , 0 ), _Names . EmpTitle ) drawField ( "EMPLOYEE NUMBER: " , fields1 ( 0 , 1 ), _Names . EmpNum ) drawField ( "STATUS: " , fields1 ( 1 , 1 ), _Names . EmpStatus ) drawField ( "DEPARTMENT: " , fields1 ( 0 , 2 ), _Names . EmpDep ) drawField ( "SUPERVISOR: " , fields1 ( 1 , 2 ), _Names . EmpSuper ) ip . Y = fields1 ( 0 , 2 ). Bottom Dim col0 = 100.0F colw = ( page . Size . Width - marginH * 2 - col0 ) / 5 Dim rowh = 25.0F Dim fields2 = DrawTable ( ip , New Single () { col0 , colw , colw , colw , colw , colw }, New Single () { 50 , rowh , rowh , rowh , rowh , rowh , rowh , rowh , rowh }, g , pen ) tl . ParagraphAlignment = ParagraphAlignment . Far drawField ( "DATE" , fields2 ( 0 , 0 ), Nothing ) drawField ( "START TIME" , fields2 ( 1 , 0 ), Nothing ) drawField ( "END TIME" , fields2 ( 2 , 0 ), Nothing ) drawField ( "REGULAR HOURS" , fields2 ( 3 , 0 ), Nothing ) drawField ( "OVERTIME HOURS" , fields2 ( 4 , 0 ), Nothing ) tf . FontBold = True drawField ( "TOTAL HOURS" , fields2 ( 5 , 0 ), Nothing ) tf . FontBold = False tl . ParagraphAlignment = ParagraphAlignment . Center tf . ForeColor = Color . Gray For i = 0 To 6 drawField ( _Names . Dows ( i ), fields2 ( 0 , i + 1 ), _Names . DtNames ( _Names . Dows ( i ))( 0 )) Next '' Vertically align date fields (compensate for different DOW widths): Dim dowFields = doc . AcroForm . Fields . TakeLast ( 7 ) Dim minW = dowFields . Min ( Function ( f_ ) CType ( f_ , TextField ). Widget . Rect . Width ) dowFields . ToList (). ForEach ( Sub ( f_ ) Dim r_ = CType ( f_ , TextField ). Widget . Rect r_ . Offset ( r_ . Width - minW , 0 ) r_ . Width = minW CType ( f_ , TextField ). Widget . Rect = r_ End Sub ) tf . ForeColor = Color . Black For row = 1 To 7 For col = 1 To 5 drawField ( Nothing , fields2 ( col , row ), _Names . DtNames ( _Names . Dows ( row - 1 ))( col )) Next Next tf . FontBold = True drawField ( "WEEKLY TOTALS" , fields2 ( 0 , 8 ), Nothing ) tf . FontBold = False drawField ( Nothing , fields2 ( 3 , 8 ), _Names . TotalReg ) drawField ( Nothing , fields2 ( 4 , 8 ), _Names . TotalOvr ) drawField ( Nothing , fields2 ( 5 , 8 ), _Names . TotalHours ) ip . Y = fields2 ( 0 , 8 ). Bottom col0 = 72 * 4 colw = page . Size . Width - marginH * 2 - col0 Dim fields3 = DrawTable ( ip , New Single () { col0 , colw }, New Single () { rowh + 10 , rowh , rowh }, g , pen ) drawField ( "EMPLOYEE SIGNATURE: " , fields3 ( 0 , 1 ), Nothing ) Dim r = fields3 ( 0 , 1 ) _empSignRect = New RectangleF ( r . X + r . Width / 2 , r . Y , r . Width / 2 - _inputMargin * 2 , r . Height ) Dim sfEmp = New SignatureField () sfEmp . Name = _Names . EmpSign sfEmp . Widget . Rect = New RectangleF ( r . X + r . Width / 2 , r . Y + _inputMargin , r . Width / 2 - _inputMargin * 2 , r . Height - _inputMargin * 2 ) sfEmp . Widget . Page = page sfEmp . Widget . BackColor = Color . LightSeaGreen doc . AcroForm . Fields . Add ( sfEmp ) drawField ( "DATE: " , fields3 ( 1 , 1 ), _Names . EmpSignDate ) drawField ( "SUPERVISOR SIGNATURE: " , fields3 ( 0 , 2 ), Nothing ) r = fields3 ( 0 , 2 ) Dim sfSup = New SignatureField () sfSup . Name = _Names . SupSign sfSup . Widget . Rect = New RectangleF ( r . X + r . Width / 2 , r . Y + _inputMargin , r . Width / 2 - _inputMargin * 2 , r . Height - _inputMargin * 2 ) sfSup . Widget . Page = page sfSup . Widget . BackColor = Color . LightYellow doc . AcroForm . Fields . Add ( sfSup ) drawField ( "DATE: " , fields3 ( 1 , 2 ), _Names . SupSignDate ) '' Done: Return doc End Function '' Simple table drawing method. Returns the array of table cell rectangles. Private Function DrawTable ( ByVal loc As PointF , ByVal widths As Single (), ByVal heights As Single (), ByVal g As GcGraphics , ByVal p As GCDRAW . Pen ) As RectangleF (,) If widths . Length = 0 OrElse heights . Length = 0 Then Throw New Exception ( "Table must have some columns and rows." ) End If Dim cells ( widths . Length , heights . Length ) As RectangleF Dim r = New RectangleF ( loc , New SizeF ( widths . Sum (), heights . Sum ())) '' Draw left borders (except for 1st one): Dim x = loc . X For i = 0 To widths . Length - 1 For j = 0 To heights . Length - 1 cells ( i , j ). X = x cells ( i , j ). Width = widths ( i ) Next If ( i > 0 ) Then g . DrawLine ( x , r . Top , x , r . Bottom , p ) End If x += widths ( i ) Next '' Draw top borders (except for 1st one): Dim y = loc . Y For j = 0 To heights . Length - 1 For i = 0 To widths . Length - 1 cells ( i , j ). Y = y cells ( i , j ). Height = heights ( j ) Next If ( j > 0 ) Then g . DrawLine ( r . Left , y , r . Right , y , p ) End If y += heights ( j ) Next '' Draw outer border: g . DrawRectangle ( r , p ) '' Done: Return cells End Function End Class