1#Copyright ReportLab Europe Ltd. 2000-2017
2#see license.txt for license details
3#history https://hg.reportlab.com/hg-public/reportlab/log/tip/docs/userguide/ch3_pdffeatures.py
4from tools.docco.rl_doc_utils import *
5
6heading1("Exposing PDF Special Capabilities")
7disc("""PDF provides a number of features to make electronic
8    document viewing more efficient and comfortable, and
9    our library exposes a number of these.""")
10
11heading2("Forms")
12disc("""The Form feature lets you create a block of graphics and text
13    once near the start of a PDF file, and then simply refer to it on
14    subsequent pages.  If you are dealing with a run of 5000 repetitive
15    business forms - for example, one-page invoices or payslips - you
16    only need to store the backdrop once and simply draw the changing
17    text on each page.  Used correctly, forms can dramatically cut
18    file size and production time, and apparently even speed things
19    up on the printer.
20    """)
21disc("""Forms do not need to refer to a whole page; anything which
22    might be repeated often should be placed in a form.""")
23disc("""The example below shows the basic sequence used.  A real
24    program would probably define the forms up front and refer to
25    them from another location.""")
26
27
28eg(examples.testforms)
29
30heading2("Links and Destinations")
31disc("""PDF supports internal hyperlinks.  There is a very wide
32    range of link types, destination types and events which
33    can be triggered by a click.  At the moment we just
34    support the basic ability to jump from one part of a document
35    to another, and to control the zoom level of the window after
36    the jump.  The bookmarkPage method defines a destination that
37    is the endpoint of a jump.""")
38#todo("code example here...")
39
40eg("""
41    canvas.bookmarkPage(name,
42                        fit="Fit",
43                        left=None,
44                        top=None,
45                        bottom=None,
46                        right=None,
47                        zoom=None
48                        )
49""")
50disc("""
51By default the $bookmarkPage$ method defines the page itself as the
52destination. After jumping to an endpoint defined by bookmarkPage,
53the PDF browser will display the whole page, scaling it to fit the
54screen:""")
55
56eg("""canvas.bookmarkPage(name)""")
57
58disc("""The $bookmarkPage$ method can be instructed to display the
59page in a number of different ways by providing a $fit$
60parameter.""")
61
62eg("")
63
64t = Table([
65           ['fit','Parameters Required','Meaning'],
66           ['Fit',None,'Entire page fits in window (the default)'],
67           ['FitH','top','Top coord at top of window, width scaled to fit'],
68           ['FitV','left','Left coord at left of window, height scaled to fit'],
69           ['FitR','left bottom right top','Scale window to fit the specified rectangle'],
70           ['XYZ','left top zoom','Fine grained control. If you omit a parameter\nthe PDF browser interprets it as "leave as is"']
71          ])
72t.setStyle(TableStyle([
73            ('FONT',(0,0),(-1,1),'Times-Bold',10,12),
74            ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
75            ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
76            ('BOX', (0,0), (-1,-1), 0.25, colors.black),
77            ]))
78
79getStory().append(t)
80caption("""Table <seq template="%(Chapter)s-%(Table+)s"/> - Required attributes for different fit types""")
81
82disc("""
83Note : $fit$ settings are case-sensitive so $fit="FIT"$ is invalid
84""")
85
86
87disc("""
88Sometimes you want the destination of a jump to be some part of a page.
89The $FitR$ fit allows you to identify a particular rectangle, scaling
90the area to fit the entire page.
91""")
92
93disc("""
94To set the display to a particular x and y coordinate of the page and to
95control the zoom directly use fit="XYZ".
96""")
97
98eg("""
99canvas.bookmarkPage('my_bookmark',fit="XYZ",left=0,top=200)
100""")
101
102
103
104disc("""
105This destination is at the leftmost of the page with the top of the screen
106at position 200. Because $zoom$ was not set the zoom remains at whatever the
107user had it set to.
108""")
109
110eg("""
111canvas.bookmarkPage('my_bookmark',fit="XYZ",left=0,top=200,zoom=2)
112""")
113
114disc("""This time zoom is set to expand the page 2X its normal size.""")
115
116disc("""
117Note  : Both $XYZ$ and $FitR$ fit types require that their positional parameters
118($top, bottom, left, right$) be specified in terms of the default user space.
119They ignore any geometric transform in effect in the canvas graphic state.
120""")
121
122
123
124pencilnote()
125
126disc("""
127<i>Note:</i> Two previous bookmark methods are supported but deprecated now
128that bookmarkPage is so general.  These are $bookmarkHorizontalAbsolute$
129and $bookmarkHorizontal$.
130""")
131
132heading3("Defining internal links")
133eg("""
134 canvas.linkAbsolute(contents, destinationname, Rect=None, addtopage=1, name=None,
135 thickness=0, color=None, dashArray=None, **kw)
136 """)
137
138disc("""
139    The $linkAbsolute$ method defines a starting point for a jump.  When the user
140    is browsing the generated document using a dynamic viewer (such as Acrobat Reader)
141    when the mouse is clicked when the pointer is within the rectangle specified
142    by $Rect$ the viewer will jump to the endpoint associated with $destinationname$.
143    As in the case with $bookmarkHorizontalAbsolute$ the rectangle $Rect$ must be
144    specified in terms of the default user space.  The $contents$ parameter specifies
145    a chunk of text which displays in the viewer if the user left-clicks on the region.
146""")
147
148disc("""
149The rectangle $Rect$ must be specified in terms of a tuple ^(x1,y1,x2,y2)^ identifying
150the lower left and upper right points of the rectangle in default user space.
151""")
152
153disc("""
154For example the code
155""")
156
157eg("""
158    canvas.bookmarkPage("Meaning_of_life")
159""")
160
161disc("""
162defines a location as the whole of the current page with the identifier
163$Meaning_of_life$.  To create a rectangular link to it while drawing a possibly
164different page, we would use this code:
165""")
166
167eg("""
168 canvas.linkAbsolute("Find the Meaning of Life", "Meaning_of_life",
169                     (inch, inch, 6*inch, 2*inch))
170""")
171
172disc("""
173By default during interactive viewing a rectangle appears around the
174link. Use the keyword argument $Border='[0 0 0]'$ to
175suppress the visible rectangle around the during viewing link.
176For example
177""")
178
179eg("""
180 canvas.linkAbsolute("Meaning of Life", "Meaning_of_life",
181                     (inch, inch, 6*inch, 2*inch), Border='[0 0 0]')
182""")
183
184disc("""The $thickness$, $color$ and $dashArray$ arguments may be used alternately
185to specify a border if no Border argument is specified.
186If Border is specified it must be either a string representation of a PDF
187array or a $PDFArray$ (see the pdfdoc module). The $color$ argument (which should be a $Color$ instance) is equivalent to a keyword argument $C$ which should resolve to a PDF color definition (Normally a three entry PDF array).
188""")
189disc("""The $canvas.linkRect$ method is similar in intent to the $linkAbsolute$ method, but has an extra argument $relative=1$ so is intended to obey the local userspace transformation.""")
190
191heading2("Outline Trees")
192disc("""Acrobat Reader has a navigation page which can hold a
193    document outline; it should normally be visible when you
194    open this guide.  We provide some simple methods to add
195    outline entries.  Typically, a program to make a document
196    (such as this user guide) will call the method
197    $canvas.addOutlineEntry(^self, title, key, level=0,
198    closed=None^)$ as it reaches each heading in the document.
199    """)
200
201disc("""^title^ is the caption which will be displayed in
202    the left pane.  The ^key^ must be a string which is
203    unique within the document and which names a bookmark,
204    as with the hyperlinks.  The ^level^ is zero - the
205    uppermost level - unless otherwise specified, and
206    it is an error to go down more than one level at a time
207    (for example to follow a level 0 heading by a level 2
208     heading).  Finally, the ^closed^ argument specifies
209    whether the node in the outline pane is closed
210    or opened by default.""")
211
212disc("""The snippet below is taken from the document template
213    that formats this user guide.  A central processor looks
214    at each paragraph in turn, and makes a new outline entry
215    when a new chapter occurs, taking the chapter heading text
216    as the caption text.  The key is obtained from the
217    chapter number (not shown here), so Chapter 2 has the
218    key 'ch2'.  The bookmark to which the
219    outline entry points aims at the whole page, but it could
220    as easily have been an individual paragraph.
221    """)
222
223eg("""
224#abridged code from our document template
225if paragraph.style == 'Heading1':
226    self.chapter = paragraph.getPlainText()
227    key = 'ch%d' % self.chapterNo
228    self.canv.bookmarkPage(key)
229    self.canv.addOutlineEntry(paragraph.getPlainText(),
230                                            key, 0, 0)
231    """)
232
233heading2("Page Transition Effects")
234
235
236eg("""
237 canvas.setPageTransition(self, effectname=None, duration=1,
238                        direction=0,dimension='H',motion='I')
239                        """)
240
241disc("""
242The $setPageTransition$ method specifies how one page will be replaced with
243the next.  By setting the page transition effect to "dissolve" for example
244the current page will appear to melt away when it is replaced by the next
245page during interactive viewing.  These effects are useful in spicing up
246slide presentations, among other places.
247Please see the reference manual for more detail on how to use this method.
248""")
249
250heading2("Internal File Annotations")
251
252eg("""
253 canvas.setAuthor(name)
254 canvas.setTitle(title)
255 canvas.setSubject(subj)
256 """)
257
258disc("""
259These methods have no automatically seen visible effect on the document.
260They add internal annotations to the document.  These annotations can be
261viewed using the "Document Info" menu item of the browser and they also can
262be used as a simple standard way of providing basic information about the
263document to archiving software which need not parse the entire
264file.  To find the annotations view the $*.pdf$ output file using a standard
265text editor (such as $notepad$ on MS/Windows or $vi$ or $emacs$ on unix) and look
266for the string $/Author$ in the file contents.
267""")
268
269eg(examples.testannotations)
270
271disc("""
272If you want the subject, title, and author to automatically display
273in the document when viewed and printed you must paint them onto the
274document like any other text.
275""")
276
277illust(examples.annotations, "Setting document internal annotations")
278
279heading2("Encryption")
280
281heading3("About encrypting PDF files")
282
283disc("""
284Adobe's PDF standard allows you to do three related things to a PDF file when you encrypt it:
285""")
286bullet("""Apply password protection to it, so a user must supply a valid password before being able to read it,
287""")
288bullet("""Encrypt the contents of the file to make it useless until it is decrypted, and
289""")
290bullet("""Control whether the user can print, copy and paste or modify the document while viewing it.
291""")
292
293disc("""
294The PDF security handler allows two different passwords to be specified for a document:
295""")
296
297bullet("""The 'owner' password (aka the 'security password' or 'master password')
298""")
299
300bullet("""The 'user' password (aka the 'open password')
301""")
302
303disc("""
304When a user supplies either one of these passwords, the PDF file will be opened, decrypted and displayed on
305screen.
306""")
307
308disc("""
309If the owner password is supplied, then the file is opened with full control - you can do anything to it,
310including changing the security settings and passwords, or re-encrypting it with a new password.
311""")
312
313disc("""
314     If the user password was the one that was supplied, you open it up in a more restricted mode. The restrictions were put in
315place when the file was encrypted, and will either allow or deny the user permission to do the following:
316""")
317
318bullet("""
319Modifying the document's contents
320""")
321
322bullet("""
323Copying text and graphics from the document
324""")
325
326bullet("""
327Adding or modifying text annotations and interactive form fields
328""")
329
330bullet("""
331Printing the document
332""")
333
334disc("""
335Note that all password protected PDF files are encrypted, but not all encrypted PDFs are password protected. If
336a document's user password is an empty string, there will be no prompt for the password when the file is
337opened. If you only secure a document with the owner password, there will also not be a prompt for the
338password when you open the file. If the owner and user passwords are set to the same string when encrypting
339the PDF file, the document will always open with the user access privileges. This means that it is possible to
340create a file which, for example, is impossible for anyone to print out, even the person who created it.
341""")
342
343t = Table([
344           ['Owner Password \nset?','User Password \nset?','Result'],
345           ['Y','-','No password required when opening file. \nRestrictions apply to everyone.'],
346           ['-','Y','User password required when opening file. \nRestrictions apply to everyone.'],
347           ['Y','Y','A password required when opening file. \nRestrictions apply only if user password supplied.'],
348          ],[90, 90, 260])
349
350t.setStyle(TableStyle([
351            ('FONT',(0,0),(-1,0),'Times-Bold',10,12),
352            ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
353            ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
354            ('BOX', (0,0), (-1,-1), 0.25, colors.black),
355            ]))
356
357getStory().append(t)
358
359disc("""
360When a PDF file is encrypted, encryption is applied to all the strings and streams in the file. This prevents
361people who don't have the password from simply removing the password from the PDF file to gain access to it -
362it renders the file useless unless you actually have the password.
363""")
364disc("""
365PDF's standard encryption methods use the
366MD5 message digest algorithm (as described in RFC 1321, The MD5 Message-Digest Algorithm) and an
367encryption algorithm known as RC4. RC4 is a symmetric stream cipher - the same algorithm is used both for
368encryption and decryption, and the algorithm does not change the length of the data.
369""")
370
371heading3("How To Use Encryption")
372
373disc("""
374     Documents can be encrypted by passing an argument to the canvas object.
375     """)
376
377disc("""
378     If the argument is a string object, it is used as the User password to the PDF.
379     """)
380
381disc("""
382     The argument can also be an instance of the class $reportlab.lib.pdfencrypt.StandardEncryption$,
383     which allows more finegrained control over encryption settings.
384     """)
385
386disc("""
387     The $StandardEncryption$ constructor takes the following arguments:
388     """)
389
390eg("""
391    def __init__(self, userPassword,
392            ownerPassword=None,
393            canPrint=1,
394            canModify=1,
395            canCopy=1,
396            canAnnotate=1,
397            strength=40):
398    """)
399
400disc("""
401     The $userPassword$ and $ownerPassword$ parameters set the relevant password on the encrypted PDF.
402     """)
403
404disc("""
405     The boolean flags $canPrint$, $canModify$, $canCopy$, $canAnnotate$ determine wether a user can
406    perform the corresponding actions on the PDF when only a user password has been supplied.
407    """)
408disc("""
409    If the user supplies the owner password while opening the PDF, all actions can be performed regardless
410    of the flags.
411    """)
412
413heading3("Example")
414
415disc("""
416     To create a document named hello.pdf with a user password of 'rptlab' on which printing is not allowed,
417     use the following code:
418     """)
419
420eg("""
421from reportlab.pdfgen import canvas
422from reportlab.lib import pdfencrypt
423
424enc=pdfencrypt.StandardEncryption("rptlab",canPrint=0)
425
426def hello(c):
427    c.drawString(100,100,"Hello World")
428c = canvas.Canvas("hello.pdf",encrypt=enc)
429hello(c)
430c.showPage()
431c.save()
432
433""")
434
435heading2("Interactive Forms")
436heading3("Overview of Interactive Forms")
437
438disc("""The PDF standard allows for various kinds of interactive elements,
439the ReportLab toolkit currently supports only a fraction of the possibilities and should be considered a work in progress.
440At present we allow choices with
441<i>checkbox</i>, <i>radio</i>, <i>choice</i> &amp; <i>listbox</i> widgets; text values can be entered with a
442<i>textfield</i> widget. All the widgets are created by calling methods on the <i>canvas.acroform</i> property."""
443)
444heading3("Example")
445disc("This shows the basic mechanism of creating an interactive element on the current page.")
446eg("""
447        canvas.acroform.checkbox(
448                name='CB0',
449                tooltip='Field CB0',
450                checked=True,
451                x=72,y=72+4*36,
452                buttonStyle='diamond',
453                borderStyle='bevelled',
454                borderWidth=2,
455                borderColor=red,
456                fillColor=green,
457                textColor=blue,
458                forceBorder=True)
459""")
460alStyle=TableStyle([
461            ('SPAN',(0,0),(-1,0)),
462            ('FONT',(0,0),(-1,0),'Helvetica-Bold',10,12),
463            ('FONT',(0,1),(-1,1),'Helvetica-BoldOblique',8,9.6),
464            ('FONT',(0,2),(0,-1),'Helvetica-Bold',7,8.4),
465            ('FONT',(1,2),(1,-1),'Helvetica',7,8.4),
466            ('FONT',(2,2),(2,-1),'Helvetica-Oblique',7,8.4),
467            ('ALIGN',(0,0),(-1,0),'CENTER'),
468            ('ALIGN',(1,1),(1,1),'CENTER'),
469            ('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
470            ('BOX', (0,0), (-1,-1), 0.25, colors.black),
471            ])
472
473disc("""<b>NB</b> note that the <i>acroform</i> canvas property is created automatically on demand and that there is only one form allowd in a document.""")
474heading3("Checkbox Usage")
475disc("""The <i>canvas.acroform.checkbox</i> method creates a <i>checkbox</i> widget on the current page. The value of the checkbox is either <b>YES</b> or <b>OFF</b>.
476The arguments are""")
477t = Table([
478            ['canvas.acroform.checkbox parameters','',''],
479            ['Parameter','Meaning','Default'],
480            ["name","the parameter's name","None"],
481            ["x","the horizontal position on the page (absolute coordinates)","0"],
482            ["y","the vertical position on the page (absolute coordinates)","0"],
483            ["size","The outline dimensions size x size","20"],
484            ["checked","if True the checkbox is initially checked","False"],
485            ["buttonStyle","the checkbox style (see below)","'check'"],
486            ["shape","The outline of the widget (see below)","'square'"],
487            ["fillColor","colour to be used to fill the widget","None"],
488            ["textColor","the colour of the symbol or text","None"],
489            ["borderWidth","as it says","1"],
490            ["borderColor","the widget's border colour","None"],
491            ["borderStyle","The border style name","'solid'"],
492            ["tooltip","The text to display when hovering over the widget","None"],
493            ["annotationFlags","blank separated string of annotation flags","'print'"],
494            ["fieldFlags","Blank separated field flags (see below)","'required'"],
495            ["forceBorder","when true a border force a border to be drawn","False"],
496            ["relative","if true obey the current canvas transform","False"],
497            ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"],
498          ],[90, 260, 90],style=alStyle,repeatRows=2)
499getStory().append(t)
500
501heading3("Radio Usage")
502disc("""The <i>canvas.acroform.radio</i> method creates a <i>radio</i> widget on the current page. The value of the radio is the value of the radio group's
503selected value or <b>OFF</b> if none are selected.
504The arguments are""")
505t = Table([
506            ['canvas.acroform.radio parameters','',''],
507            ['Parameter','Meaning','Default'],
508            ["name","the radio's group (ie parameter) name","None"],
509            ["value","the radio's group name","None"],
510            ["x","the horizontal position on the page (absolute coordinates)","0"],
511            ["y","the vertical position on the page (absolute coordinates)","0"],
512            ["size","The outline dimensions size x size","20"],
513            ["selected","if True this radio is the selected one in its group","False"],
514            ["buttonStyle","the checkbox style (see below)","'check'"],
515            ["shape","The outline of the widget (see below)","'square'"],
516            ["fillColor","colour to be used to fill the widget","None"],
517            ["textColor","the colour of the symbol or text","None"],
518            ["borderWidth","as it says","1"],
519            ["borderColor","the widget's border colour","None"],
520            ["borderStyle","The border style name","'solid'"],
521            ["tooltip","The text to display when hovering over the widget","None"],
522            ["annotationFlags","blank separated string of annotation flags","'print'"],
523            ["fieldFlags","Blank separated field flags (see below)","'noToggleToOff required radio'"],
524            ["forceBorder","when true a border force a border to be drawn","False"],
525            ["relative","if true obey the current canvas transform","False"],
526            ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"],
527          ],[90, 260, 90],style=alStyle,repeatRows=2)
528getStory().append(t)
529heading3("Listbox Usage")
530disc("""The <i>canvas.acroform.listbox</i> method creates a <i>listbox</i> widget on the current page. The listbox contains a
531list of options one or more of which (depending on fieldFlags) may be selected.
532""")
533t = Table([
534            ['canvas.acroform.listbox parameters','',''],
535            ['Parameter','Meaning','Default'],
536            ["name","the radio's group (ie parameter) name","None"],
537            ["options","List or tuple of avaiable options","[]"],
538            ["value","Singleton or list of strings of selected options","[]"],
539            ["x","the horizontal position on the page (absolute coordinates)","0"],
540            ["y","the vertical position on the page (absolute coordinates)","0"],
541            ["width","The widget width","120"],
542            ["height","The widget height","36"],
543            ["fontName","The name of the type 1 font to be used","'Helvetica'"],
544            ["fontSize","The size of font to be used","12"],
545            ["fillColor","colour to be used to fill the widget","None"],
546            ["textColor","the colour of the symbol or text","None"],
547            ["borderWidth","as it says","1"],
548            ["borderColor","the widget's border colour","None"],
549            ["borderStyle","The border style name","'solid'"],
550            ["tooltip","The text to display when hovering over the widget","None"],
551            ["annotationFlags","blank separated string of annotation flags","'print'"],
552            ["fieldFlags","Blank separated field flags (see below)","''"],
553            ["forceBorder","when true a border force a border to be drawn","False"],
554            ["relative","if true obey the current canvas transform","False"],
555            ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"],
556          ],[90, 260, 90],style=alStyle,repeatRows=2)
557getStory().append(t)
558heading3("Choice Usage")
559disc("""The <i>canvas.acroform.choice</i> method creates a <i>dropdown</i> widget on the current page. The dropdown contains a
560list of options one or more of which (depending on fieldFlags) may be selected. If you add <i>edit</i> to the <i>fieldFlags</i>
561then the result may be edited.
562""")
563t = Table([
564            ['canvas.acroform.choice parameters','',''],
565            ['Parameter','Meaning','Default'],
566            ["name","the radio's group (ie parameter) name","None"],
567            ["options","List or tuple of avaiable options","[]"],
568            ["value","Singleton or list of strings of selected options","[]"],
569            ["x","the horizontal position on the page (absolute coordinates)","0"],
570            ["y","the vertical position on the page (absolute coordinates)","0"],
571            ["width","The widget width","120"],
572            ["height","The widget height","36"],
573            ["fontName","The name of the type 1 font to be used","'Helvetica'"],
574            ["fontSize","The size of font to be used","12"],
575            ["fillColor","colour to be used to fill the widget","None"],
576            ["textColor","the colour of the symbol or text","None"],
577            ["borderWidth","as it says","1"],
578            ["borderColor","the widget's border colour","None"],
579            ["borderStyle","The border style name","'solid'"],
580            ["tooltip","The text to display when hovering over the widget","None"],
581            ["annotationFlags","blank separated string of annotation flags","'print'"],
582            ["fieldFlags","Blank separated field flags (see below)","'combo'"],
583            ["forceBorder","when true a border force a border to be drawn","False"],
584            ["relative","if true obey the current canvas transform","False"],
585            ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"],
586            ["maxlen ","None or maximum length of the widget value","None"],
587          ],[90, 260, 90],style=alStyle,repeatRows=2)
588getStory().append(t)
589
590heading3("Textfield Usage")
591disc("""The <i>canvas.acroform.textfield</i> method creates a <i>textfield</i> entry widget on the current page. The textfield may be edited
592to change tha value of the widget
593""")
594t = Table([
595            ['canvas.acroform.textfield parameters','',''],
596            ['Parameter','Meaning','Default'],
597            ["name","the radio's group (ie parameter) name","None"],
598            ["value","Value of the text field","''"],
599            ["maxlen ","None or maximum length of the widget value","100"],
600            ["x","the horizontal position on the page (absolute coordinates)","0"],
601            ["y","the vertical position on the page (absolute coordinates)","0"],
602            ["width","The widget width","120"],
603            ["height","The widget height","36"],
604            ["fontName","The name of the type 1 font to be used","'Helvetica'"],
605            ["fontSize","The size of font to be used","12"],
606            ["fillColor","colour to be used to fill the widget","None"],
607            ["textColor","the colour of the symbol or text","None"],
608            ["borderWidth","as it says","1"],
609            ["borderColor","the widget's border colour","None"],
610            ["borderStyle","The border style name","'solid'"],
611            ["tooltip","The text to display when hovering over the widget","None"],
612            ["annotationFlags","blank separated string of annotation flags","'print'"],
613            ["fieldFlags","Blank separated field flags (see below)","''"],
614            ["forceBorder","when true a border force a border to be drawn","False"],
615            ["relative","if true obey the current canvas transform","False"],
616            ["dashLen ","the dashline to be used if the borderStyle=='dashed'","3"],
617          ],[90, 260, 90],style=alStyle,repeatRows=2)
618getStory().append(t)
619
620heading3("Button styles")
621disc("""The button style argument indicates what style of symbol should appear in the button when it is selected. There are several choices""")
622eg("""  check
623  cross
624  circle
625  star
626  diamond
627""")
628disc("""note that the document renderer can make some of these symbols wrong for their intended application.  Acrobat reader
629prefers to use its own rendering on top of what the specification says should be shown (especially when the forms hihlighting features are used""")
630
631heading3("Widget shape")
632disc("""The shape argument describes how the outline of the checkbox or radio widget should appear you can use""")
633eg("""  circle
634  square
635""")
636
637disc("""The renderer may make its own decisions about how the widget should look; so Acrobat Reader prefers circular outlines for radios.""")
638
639heading3("Border style")
640disc("""The borderStyle argument changes the 3D appearance of the widget on the page alternatives are""")
641eg("""  solid
642  dashed
643  inset
644  bevelled
645  underlined
646    """)
647heading3("fieldFlags Argument")
648disc("""The fieldFlags arguments can be an integer or a string containing blank separate tokens the values are shown in the table below. For
649more information consult the PDF specification.""")
650t = Table([
651            ['Field Flag Tokens and values','',''],
652            ['Token','Meaning','Value'],
653            ["readOnly","The widget is read only","1<<0"],
654            ["required","the widget is required","1<<1"],
655            ["noExport","don't export the widget value","1<<2"],
656            ["noToggleToOff","radios one only must be on","1<<14"],
657            ["radio","added by the radio method","1<<15"],
658            ["pushButton","if the button is a push button","1<<16"],
659            ["radiosInUnison","radios with the same value toggle together","1<<25"],
660            ["multiline","for multiline text widget","1<<12"],
661            ["password","password textfield","1<<13"],
662            ["fileSelect","file selection widget","1<<20"],         #1.4
663            ["doNotSpellCheck","as it says","1<<22"],   #1.4
664            ["doNotScroll","text fields do not scroll","1<<23"],        #1.4
665            ["comb","make a comb style text based on the maxlen value","1<<24"],                #1.5
666            ["richText","if rich text is used","1<<25"],            #1.5
667            ["combo","for choice fields","1<<17"],
668            ["edit","if the choice is editable","1<<18"],
669            ["sort","if the values should be sorted","1<<19"],
670            ["multiSelect","if the choice allows multi-select","1<<21"],        #1.4
671            ["commitOnSelChange","not used by reportlab","1<<26"],  #1.5
672          ],[90, 260, 90],style=alStyle,repeatRows=2)
673getStory().append(t)
674heading3("annotationFlags Argument")
675disc("""PDF widgets are annotations and have annotation properties these are shown in the table below""")
676t = Table([
677            ['Annotation Flag Tokens and values','',''],
678            ['Token','Meaning','Value'],
679            ["invisible","The widget is not shown","1<<0"],
680            ["hidden","The widget is hidden","1<<1"],
681            ["print","The widget will print","1<<2"],
682            ["nozoom","The annotation will notscale with the rendered page","1<<3"],
683            ["norotate","The widget won't rotate with the page","1<<4"],
684            ["noview","Don't render the widget","1<<5"],
685            ["readonly","Widget cannot be interacted with","1<<6"],
686            ["locked","The widget cannot be changed","1<<7"],           #1.4
687            ["togglenoview","Teh widget may be viewed after some events","1<<8"],       #1.9
688            ["lockedcontents","The contents of the widget are fixed","1<<9"],   #1.7
689          ],[90, 260, 90],style=alStyle)
690getStory().append(t)
691