reportlab/platypus/flowables.py
author rgbecker
Wed, 25 Oct 2000 08:57:46 +0000
changeset 494 54257447cfe9
parent 445 8b64b9812ca6
child 496 bb47cf5c2739
permissions -rw-r--r--
Changed to indirect copyright
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
494
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 445
diff changeset
     1
#copyright ReportLab Inc. 2000
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 445
diff changeset
     2
#see license.txt for license details
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 445
diff changeset
     3
#history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/platypus/flowables.py?cvsroot=reportlab
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 445
diff changeset
     4
#$Header: /tmp/reportlab/reportlab/platypus/flowables.py,v 1.10 2000/10/25 08:57:45 rgbecker Exp $
54257447cfe9 Changed to indirect copyright
rgbecker
parents: 445
diff changeset
     5
__version__=''' $Id: flowables.py,v 1.10 2000/10/25 08:57:45 rgbecker Exp $ '''
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
     6
__doc__="""
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
     7
A flowable is a "floating element" in a document whose exact position is determined by the
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
     8
other elements that precede it, such as a paragraph, a diagram interspersed between paragraphs,
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
     9
a section header, etcetera.  Examples of non-flowables include page numbering annotations,
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    10
headers, footers, fixed diagrams or logos, among others.
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    11
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    12
Flowables are defined here as objects which know how to determine their size and which
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    13
can draw themselves onto a page with respect to a relative "origin" position determined
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    14
at a higher level. The object's draw() method should assume that (0,0) corresponds to the
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    15
bottom left corner of the enclosing rectangle that will contain the object. The attributes
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    16
vAlign and hAlign may be used by 'packers' as hints as to how the object should be placed.
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    17
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    18
Some Flowables also know how to "split themselves".  For example a
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    19
long paragraph might split itself between one page and the next.
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    20
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    21
The "text" of a document usually consists mainly of a sequence of flowables which
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    22
flow into a document from top to bottom (with column and page breaks controlled by
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
    23
higher level components).
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    24
"""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    25
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    26
# 200-10-13 gmcm
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    27
#	packagizing
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    28
#	rewrote grid stuff - now in tables.py
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    29
import os
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    30
import string
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    31
from copy import deepcopy
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
    32
from types import ListType, TupleType
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    33
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    34
from reportlab.pdfgen import canvas
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    35
from reportlab.lib.units import inch
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    36
from reportlab.lib.colors import red
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    37
from reportlab.pdfbase import pdfutils
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    38
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    39
from reportlab.lib.pagesizes import DEFAULT_PAGE_SIZE
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    40
PAGE_HEIGHT = DEFAULT_PAGE_SIZE[1]
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    41
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    42
#############################################################
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    43
#	Flowable Objects - a base class and a few examples.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    44
#	One is just a box to get some metrics.	We also have
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    45
#	a paragraph, an image and a special 'page break'
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    46
#	object which fills the space.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    47
#############################################################
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    48
class Flowable:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    49
	"""Abstract base class for things to be drawn.	Key concepts:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    50
	1. It knows its size
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    51
	2. It draws in its own coordinate system (this requires the
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    52
		base API to provide a translate() function.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    53
	"""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    54
	def __init__(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    55
		self.width = 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    56
		self.height = 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    57
		self.wrapped = 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    58
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    59
		#these are hints to packers/frames as to how the floable should be positioned
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    60
		self.hAlign = 'LEFT'	#CENTER/CENTRE or RIGHT
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    61
		self.vAlign = 'BOTTOM'	#MIDDLE or TOP
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    62
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    63
	def drawOn(self, canvas, x, y, _sW=0):
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    64
		"Tell it to draw itself on the canvas.	Do not override"
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    65
		if _sW and hasattr(self,'hAlign'):
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    66
			a = self.hAlign
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    67
			if a in ['CENTER','CENTRE']:
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    68
				x = x + 0.5*_sW
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    69
			elif a == 'RIGHT':
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    70
				x = x + _sW
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    71
			elif a != 'LEFT':
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    72
				raise ValueError, "Bad hAlign value "+str(a)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    73
		self.canv = canvas
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    74
		self.canv.saveState()
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    75
		self.canv.translate(x, y)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    76
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    77
		self.draw()   #this is the bit you overload
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    78
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    79
		self.canv.restoreState()
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    80
		del self.canv
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    81
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    82
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    83
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    84
		"""This will be called by the enclosing frame before objects
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    85
		are asked their size, drawn or whatever.  It returns the
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    86
		size actually used."""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    87
		return (self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    88
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    89
	def split(self, availWidth, availheight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    90
		"""This will be called by more sophisticated frames when
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    91
		wrap fails. Stupid flowables should return []. Clever flowables
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    92
		should split themselves and return a list of flowables"""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    93
		return []
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    94
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    95
	def getSpaceAfter(self):
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
    96
		"""returns how much space should follow this item if another item follows on the same page."""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    97
		if hasattr(self,'spaceAfter'): return self.spaceAfter
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    98
		elif hasattr(self,'style') and hasattr(self.style,'spaceAfter'): return self.style.spaceAfter
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    99
		else: return 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   100
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   101
	def getSpaceBefore(self):
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   102
		"""returns how much space should precede this item if another item precedess on the same page."""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   103
		if hasattr(self,'spaceBefore'): return self.spaceBefore
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   104
		elif hasattr(self,'style') and hasattr(self.style,'spaceBefore'): return self.style.spaceBefore
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   105
		else: return 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   106
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   107
class XBox(Flowable):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   108
	"""Example flowable - a box with an x through it and a caption.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   109
	This has a known size, so does not need to respond to wrap()."""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   110
	def __init__(self, width, height, text = 'A Box'):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   111
		Flowable.__init__(self)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   112
		self.width = width
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   113
		self.height = height
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   114
		self.text = text
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   115
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   116
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   117
		self.canv.rect(0, 0, self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   118
		self.canv.line(0, 0, self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   119
		self.canv.line(0, self.height, self.width, 0)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   120
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   121
		#centre the text
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   122
		self.canv.setFont('Times-Roman',12)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   123
		self.canv.drawCentredString(0.5*self.width, 0.5*self.height, self.text)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   124
445
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   125
def _trimEmptyLines(lines):
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   126
	#don't want the first or last to be empty
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   127
	while len(lines) and string.strip(lines[0]) == '':
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   128
		lines = lines[1:]
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   129
	while len(lines) and string.strip(lines[-1]) == '':
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   130
		lines = lines[:-1]
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   131
	return lines
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   132
442
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   133
def _dedenter(text,dedent=0):
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   134
	'''
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   135
	tidy up text - carefully, it is probably code.  If people want to
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   136
	indent code within a source script, you can supply an arg to dedent
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   137
	and it will chop off that many character, otherwise it leaves
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   138
	left edge intact.
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   139
	'''
445
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   140
	lines = string.split(text, '\n')
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   141
	if dedent>0:
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   142
		templines = _trimEmptyLines(lines)
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   143
		lines = []
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   144
		for line in templines:
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   145
			line = string.rstrip(line[dedent:])
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   146
			lines.append(line)
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   147
	else:
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   148
		lines = _trimEmptyLines(lines)
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   149
442
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   150
	return lines
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   151
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   152
class Preformatted(Flowable):
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   153
	"""This is like the HTML <PRE> tag.  
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   154
	It attempts to display text exactly as you typed it in a fixed width "typewriter" font.
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   155
	The line breaks are exactly where you put
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   156
	them, and it will not be wrapped."""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   157
	def __init__(self, text, style, bulletText = None, dedent=0):
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   158
		"""text is the text to display. If dedent is set then common leading space
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   159
		will be chopped off the front (for example if the entire text is indented
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   160
		6 spaces or more then each line will have 6 spaces removed from the front).
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   161
		"""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   162
		self.style = style
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   163
		self.bulletText = bulletText
442
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   164
		self.lines = _dedenter(text,dedent)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   165
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   166
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   167
		self.width = availWidth
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   168
		self.height = self.style.leading*len(self.lines)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   169
		return (self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   170
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   171
	def split(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   172
		#returns two Preformatted objects
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   173
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   174
		#not sure why they can be called with a negative height		
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   175
		if availHeight < self.style.leading:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   176
			return []
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   177
		
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   178
		linesThatFit = int(availHeight * 1.0 / self.style.leading)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   179
		
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   180
		text1 = string.join(self.lines[0:linesThatFit], '\n')
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   181
		text2 = string.join(self.lines[linesThatFit:], '\n')
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   182
		style = self.style
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   183
		if style.firstLineIndent != 0:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   184
			style = deepcopy(style)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   185
			style.firstLineIndent = 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   186
		return [Preformatted(text1, self.style), Preformatted(text2, style)]
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   187
		
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   188
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   189
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   190
		#call another method for historical reasons.  Besides, I
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   191
		#suspect I will be playing with alternate drawing routines
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   192
		#so not doing it here makes it easier to switch.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   193
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   194
		cur_x = self.style.leftIndent
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   195
		cur_y = self.height - self.style.fontSize
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   196
		self.canv.addLiteral('%PreformattedPara')
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   197
		if self.style.textColor:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   198
			self.canv.setFillColor(self.style.textColor)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   199
		tx = self.canv.beginText(cur_x, cur_y)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   200
		#set up the font etc.
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   201
		tx.setFont(	self.style.fontName,
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   202
					self.style.fontSize,
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   203
					self.style.leading)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   204
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   205
		for text in self.lines:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   206
			tx.textLine(text)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   207
		self.canv.drawText(tx)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   208
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   209
class Image(Flowable):
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   210
	"""an image (digital picture).  Formats supported by PIL (the Python Imaging Library
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   211
	   are supported.  At the present time images as flowables are always centered horozontally
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   212
	   in the frame.
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   213
	"""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   214
	def __init__(self, filename, width=None, height=None):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   215
		"""If size to draw at not specified, get it from the image."""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   216
		import Image  #this will raise an error if they do not have PIL.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   217
		self.filename = filename
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
   218
		self.hAlign = 'CENTER'
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   219
		# if it is a JPEG, will be inlined within the file -
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   220
		# but we still need to know its size now
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   221
		if os.path.splitext(filename)[1] in ['.jpg', '.JPG', '.jpeg', '.JPEG']:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   222
			info = pdfutils.readJPEGInfo(open(filename, 'rb'))
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   223
			self.imageWidth = info[0]
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   224
			self.imageHeight = info[1]
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   225
		else:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   226
			img = Image.open(filename)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   227
			(self.imageWidth, self.imageHeight) = img.size
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   228
		if width:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   229
			self.drawWidth = width
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   230
		else:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   231
			self.drawWidth = self.imageWidth
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   232
		if height:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   233
			self.drawHeight = height
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   234
		else:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   235
			self.drawHeight = self.imageHeight
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   236
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   237
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   238
		#the caller may decide it does not fit.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   239
		return (self.drawWidth, self.drawHeight)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   240
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   241
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   242
		#center it
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   243
		self.canv.drawInlineImage(self.filename,
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
   244
								0,
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   245
								0,
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   246
								self.drawWidth,
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   247
								self.drawHeight
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   248
								)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   249
class Spacer(Flowable):
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   250
	"""A spacer just takes up space and doesn't draw anything - it guarantees
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   251
	   a gap between objects."""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   252
	def __init__(self, width, height):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   253
		self.width = width
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   254
		self.height = height
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   255
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   256
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   257
		return (self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   258
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   259
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   260
		pass
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   261
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   262
class PageBreak(Spacer):
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   263
	"""Move on to the next page in the document.
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   264
	   This works by consuming all remaining space in the frame!"""
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   265
	def __init__(self):
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   266
		pass
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   267
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   268
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   269
		self.width = availWidth
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   270
		self.height = availHeight
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   271
		return (availWidth,availHeight)  #step back a point
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   272
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   273
class CondPageBreak(Spacer):
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   274
	"""Throw a page if not enough vertical space"""
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   275
	def __init__(self, height):
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   276
		self.height = height
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   277
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   278
	def wrap(self, availWidth, availHeight):
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   279
		if availHeight<self.height:
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   280
			return (availWidth, availHeight)
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   281
		return (0, 0)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   282
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   283
_SeqTypes = (ListType, TupleType)
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   284
class KeepTogether(Flowable):
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   285
	def __init__(self,flowables):
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   286
		if type(flowables) not in _SeqTypes:
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   287
			self._flowables = [flowables]
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   288
		else:
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   289
			self._flowables = flowables
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   290
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   291
	def wrap(self, aW, aH):
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   292
		W = 0
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   293
		H = 0
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   294
		F = self._flowables
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   295
		for f in F:
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   296
			w,h = f.wrap(aW,0xfffffff)
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   297
			if f is not F[0]: h = h + f.getSpaceBefore()
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   298
			if f is not F[-1]: h = h + f.getSpaceAfter()
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   299
			W = max(W,w)
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   300
			H = H+h
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   301
		self._CPage = H>aH
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   302
		return W, 0xffffff	# force a split
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   303
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   304
	def split(self, aW, aH):
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   305
		S = self._CPage and [CondPageBreak(aH+1)] or []
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   306
		for f in self._flowables: S.append(f)
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   307
		return S
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   308
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   309
class Macro(Flowable):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   310
	"""This is not actually drawn (i.e. it has zero height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   311
	but is executed when it would fit in the frame.  Allows direct
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   312
	access to the canvas through the object 'canvas'"""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   313
	def __init__(self, command):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   314
		self.command = command
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   315
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   316
		return (0,0)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   317
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   318
		exec self.command in globals(), {'canvas':self.canv}