reportlab/platypus/flowables.py
author rgbecker
Mon, 01 Oct 2001 09:58:42 +0000
changeset 1268 158ffc339d38
parent 1103 857af510186d
child 1360 f541f401eef7
permissions -rw-r--r--
Fixed slight buglet in checkpagesize
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
1103
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
     4
#$Header: /tmp/reportlab/reportlab/platypus/flowables.py,v 1.21 2001/08/01 13:01:44 rgbecker Exp $
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
     5
__version__=''' $Id: flowables.py,v 1.21 2001/08/01 13:01:44 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
import os
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    26
import string
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    27
from copy import deepcopy
557
0ed50942f243 Allow for non string file names in Image.__init__
rgbecker
parents: 541
diff changeset
    28
from types import ListType, TupleType, StringType
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    29
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    30
from reportlab.pdfgen import canvas
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    31
from reportlab.lib.units import inch
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    32
from reportlab.lib.colors import red
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    33
from reportlab.pdfbase import pdfutils
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    34
724
0b10945bd324 Renamed config.py to rl_config.py
rgbecker
parents: 684
diff changeset
    35
from reportlab.rl_config import defaultPageSize
684
2a43c747527a Changed things to use config.py for defaults
rgbecker
parents: 558
diff changeset
    36
PAGE_HEIGHT = defaultPageSize[1]
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    37
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    38
#############################################################
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    39
#	Flowable Objects - a base class and a few examples.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    40
#	One is just a box to get some metrics.	We also have
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    41
#	a paragraph, an image and a special 'page break'
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    42
#	object which fills the space.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    43
#############################################################
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    44
class Flowable:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    45
	"""Abstract base class for things to be drawn.	Key concepts:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    46
	1. It knows its size
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    47
	2. It draws in its own coordinate system (this requires the
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    48
		base API to provide a translate() function.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    49
	"""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    50
	def __init__(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    51
		self.width = 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    52
		self.height = 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    53
		self.wrapped = 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    54
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    55
		#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
    56
		self.hAlign = 'LEFT'	#CENTER/CENTRE or RIGHT
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    57
		self.vAlign = 'BOTTOM'	#MIDDLE or TOP
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    58
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    59
	def drawOn(self, canvas, x, y, _sW=0):
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    60
		"Tell it to draw itself on the canvas.	Do not override"
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    61
		if _sW and hasattr(self,'hAlign'):
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    62
			a = self.hAlign
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    63
			if a in ['CENTER','CENTRE']:
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    64
				x = x + 0.5*_sW
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    65
			elif a == 'RIGHT':
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    66
				x = x + _sW
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    67
			elif a != 'LEFT':
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
    68
				raise ValueError, "Bad hAlign value "+str(a)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    69
		self.canv = canvas
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    70
		self.canv.saveState()
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    71
		self.canv.translate(x, y)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    72
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    73
		self.draw()   #this is the bit you overload
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    74
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    75
		self.canv.restoreState()
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    76
		del self.canv
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    77
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    78
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    79
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    80
		"""This will be called by the enclosing frame before objects
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    81
		are asked their size, drawn or whatever.  It returns the
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    82
		size actually used."""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    83
		return (self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
    84
954
bf9f434cb08a added minWidth method to Flowable, Paragraph
rgbecker
parents: 760
diff changeset
    85
	def minWidth(self):
bf9f434cb08a added minWidth method to Flowable, Paragraph
rgbecker
parents: 760
diff changeset
    86
		"""This should return the minimum required width"""
bf9f434cb08a added minWidth method to Flowable, Paragraph
rgbecker
parents: 760
diff changeset
    87
		return getattr(self,'_minWidth',self.width)
bf9f434cb08a added minWidth method to Flowable, Paragraph
rgbecker
parents: 760
diff changeset
    88
253
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
512
c12ae96634d5 Added working table of contents framework
andy_robinson
parents: 496
diff changeset
   107
	def isIndexing(self):
c12ae96634d5 Added working table of contents framework
andy_robinson
parents: 496
diff changeset
   108
		"""Hook for IndexingFlowables - things which have cross references"""
c12ae96634d5 Added working table of contents framework
andy_robinson
parents: 496
diff changeset
   109
		return 0
c12ae96634d5 Added working table of contents framework
andy_robinson
parents: 496
diff changeset
   110
1103
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   111
	def identity(self, maxLen=None):
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   112
		'''
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   113
		This method should attempt to return a string that can be used to identify
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   114
		a particular flowable uniquely. The result can then be used for debugging
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   115
		and or error printouts
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   116
		'''
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   117
		if hasattr(self, 'getPlainText'):
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   118
			r = self.getPlainText()
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   119
		elif hasattr(self, 'text'):
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   120
			r = self.text
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   121
		else:
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   122
			r = '...'
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   123
		if r and maxLen:
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   124
			r = r[:maxLen]
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   125
		return "<%s at %d>%s" % (self.__class__.__name__, id(self), r)
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   126
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   127
class XBox(Flowable):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   128
	"""Example flowable - a box with an x through it and a caption.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   129
	This has a known size, so does not need to respond to wrap()."""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   130
	def __init__(self, width, height, text = 'A Box'):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   131
		Flowable.__init__(self)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   132
		self.width = width
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   133
		self.height = height
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   134
		self.text = text
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   135
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   136
	def __repr__(self):
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   137
		return "XBox(w=%s, h=%s, t=%s)" % (self.width, self.height, self.text)
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   138
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   139
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   140
		self.canv.rect(0, 0, self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   141
		self.canv.line(0, 0, self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   142
		self.canv.line(0, self.height, self.width, 0)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   143
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   144
		#centre the text
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   145
		self.canv.setFont('Times-Roman',12)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   146
		self.canv.drawCentredString(0.5*self.width, 0.5*self.height, self.text)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   147
445
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   148
def _trimEmptyLines(lines):
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   149
	#don't want the first or last to be empty
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   150
	while len(lines) and string.strip(lines[0]) == '':
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   151
		lines = lines[1:]
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   152
	while len(lines) and string.strip(lines[-1]) == '':
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   153
		lines = lines[:-1]
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   154
	return lines
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   155
442
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   156
def _dedenter(text,dedent=0):
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   157
	'''
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   158
	tidy up text - carefully, it is probably code.  If people want to
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   159
	indent code within a source script, you can supply an arg to dedent
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   160
	and it will chop off that many character, otherwise it leaves
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   161
	left edge intact.
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   162
	'''
445
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   163
	lines = string.split(text, '\n')
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   164
	if dedent>0:
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   165
		templines = _trimEmptyLines(lines)
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   166
		lines = []
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   167
		for line in templines:
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   168
			line = string.rstrip(line[dedent:])
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   169
			lines.append(line)
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   170
	else:
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   171
		lines = _trimEmptyLines(lines)
8b64b9812ca6 Fixes to _dedenter
rgbecker
parents: 442
diff changeset
   172
442
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   173
	return lines
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   174
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   175
class Preformatted(Flowable):
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   176
	"""This is like the HTML <PRE> tag.  
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   177
	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
   178
	The line breaks are exactly where you put
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   179
	them, and it will not be wrapped."""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   180
	def __init__(self, text, style, bulletText = None, dedent=0):
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   181
		"""text is the text to display. If dedent is set then common leading space
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   182
		will be chopped off the front (for example if the entire text is indented
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   183
		6 spaces or more then each line will have 6 spaces removed from the front).
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   184
		"""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   185
		self.style = style
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   186
		self.bulletText = bulletText
442
e3eac15cddbd XPreformatted first fixes; now runs
rgbecker
parents: 426
diff changeset
   187
		self.lines = _dedenter(text,dedent)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   188
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   189
	def __repr__(self):
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   190
		bT = self.bulletText
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   191
		H = "Preformatted("
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   192
		if bT is not None:
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   193
			H = "Preformatted(bulletText=%s," % repr(bT)
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   194
		import string
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   195
		text = join(self.lines, "\n")
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   196
		return "%s'''\\ \n%s''')" % (H, text)
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   197
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   198
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   199
		self.width = availWidth
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   200
		self.height = self.style.leading*len(self.lines)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   201
		return (self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   202
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   203
	def split(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   204
		#returns two Preformatted objects
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   205
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   206
		#not sure why they can be called with a negative height		
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   207
		if availHeight < self.style.leading:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   208
			return []
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   209
		
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   210
		linesThatFit = int(availHeight * 1.0 / self.style.leading)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   211
		
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   212
		text1 = string.join(self.lines[0:linesThatFit], '\n')
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   213
		text2 = string.join(self.lines[linesThatFit:], '\n')
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   214
		style = self.style
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   215
		if style.firstLineIndent != 0:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   216
			style = deepcopy(style)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   217
			style.firstLineIndent = 0
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   218
		return [Preformatted(text1, self.style), Preformatted(text2, style)]
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   219
		
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   220
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   221
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   222
		#call another method for historical reasons.  Besides, I
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   223
		#suspect I will be playing with alternate drawing routines
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   224
		#so not doing it here makes it easier to switch.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   225
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   226
		cur_x = self.style.leftIndent
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   227
		cur_y = self.height - self.style.fontSize
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   228
		self.canv.addLiteral('%PreformattedPara')
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   229
		if self.style.textColor:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   230
			self.canv.setFillColor(self.style.textColor)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   231
		tx = self.canv.beginText(cur_x, cur_y)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   232
		#set up the font etc.
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   233
		tx.setFont(	self.style.fontName,
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   234
					self.style.fontSize,
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   235
					self.style.leading)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   236
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   237
		for text in self.lines:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   238
			tx.textLine(text)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   239
		self.canv.drawText(tx)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   240
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   241
class Image(Flowable):
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   242
	"""an image (digital picture).  Formats supported by PIL (the Python Imaging Library
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   243
	   are supported.  At the present time images as flowables are always centered horozontally
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   244
	   in the frame.
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   245
	"""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   246
	def __init__(self, filename, width=None, height=None):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   247
		"""If size to draw at not specified, get it from the image."""
760
0e51a12a0e39 Changed to PIL_Image
rgbecker
parents: 724
diff changeset
   248
		from reportlab.lib.utils import PIL_Image  #this will raise an error if they do not have PIL.
1103
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   249
		self._filename = self.filename = filename
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
   250
		self.hAlign = 'CENTER'
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   251
		# if it is a JPEG, will be inlined within the file -
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   252
		# but we still need to know its size now
557
0ed50942f243 Allow for non string file names in Image.__init__
rgbecker
parents: 541
diff changeset
   253
		if type(filename) is StringType and os.path.splitext(filename)[1] in ['.jpg', '.JPG', '.jpeg', '.JPEG']:
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   254
			info = pdfutils.readJPEGInfo(open(filename, 'rb'))
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   255
			self.imageWidth = info[0]
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   256
			self.imageHeight = info[1]
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   257
		else:
1036
18b1e459dad0 Forced non string filenames to put image data into filename
rgbecker
parents: 954
diff changeset
   258
			# we have to assume this is a file like object
1103
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   259
			self.filename = img = PIL_Image.open(filename)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   260
			(self.imageWidth, self.imageHeight) = img.size
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   261
		if width:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   262
			self.drawWidth = width
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   263
		else:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   264
			self.drawWidth = self.imageWidth
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   265
		if height:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   266
			self.drawHeight = height
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   267
		else:
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   268
			self.drawHeight = self.imageHeight
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   269
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   270
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   271
		#the caller may decide it does not fit.
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   272
		return (self.drawWidth, self.drawHeight)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   273
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   274
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   275
		#center it
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   276
		self.canv.drawInlineImage(self.filename,
426
36a228f3e085 Changing to packer led positioning
rgbecker
parents: 368
diff changeset
   277
								0,
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   278
								0,
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   279
								self.drawWidth,
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   280
								self.drawHeight
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   281
								)
1103
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   282
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   283
	def identity(self,maxLen):
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   284
		r = Flowable.identity(self,maxLen)
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   285
		if r[-4:]=='>...' and type(self._filename) is StringType:
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   286
			r = "%s filename=%s>" % (r[:-4],self._filename)
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   287
		return r
857af510186d Added identity method to Flowables
rgbecker
parents: 1036
diff changeset
   288
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   289
class Spacer(Flowable):
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   290
	"""A spacer just takes up space and doesn't draw anything - it guarantees
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   291
	   a gap between objects."""
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   292
	def __init__(self, width, height):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   293
		self.width = width
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   294
		self.height = height
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   295
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   296
	def __repr__(self):
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   297
		return "Spacer(%s, %s)" % (self.width, self.height)
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   298
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   299
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   300
		return (self.width, self.height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   301
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   302
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   303
		pass
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   304
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   305
class PageBreak(Spacer):
268
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   306
	"""Move on to the next page in the document.
8414113fa500 more documentation changes
aaron_watters
parents: 255
diff changeset
   307
	   This works by consuming all remaining space in the frame!"""
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   308
	def __init__(self):
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   309
		pass
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   310
	
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   311
	def __repr__(self):
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   312
		return "PageBreak()"
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   313
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   314
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   315
		self.width = availWidth
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   316
		self.height = availHeight
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   317
		return (availWidth,availHeight)  #step back a point
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   318
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   319
class CondPageBreak(Spacer):
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   320
	"""Throw a page if not enough vertical space"""
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   321
	def __init__(self, height):
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   322
		self.height = height
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   323
		
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   324
	def __repr__(self):
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   325
		return "CondPageBreak(%s)" %(self.height,)
307
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   326
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   327
	def wrap(self, availWidth, availHeight):
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   328
		if availHeight<self.height:
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   329
			return (availWidth, availHeight)
c439e402b404 Added CondPageBreak
rgbecker
parents: 268
diff changeset
   330
		return (0, 0)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   331
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   332
_SeqTypes = (ListType, TupleType)
558
f9013e25af9d Added a random text module
andy_robinson
parents: 557
diff changeset
   333
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   334
class KeepTogether(Flowable):
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   335
	def __init__(self,flowables):
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   336
		if type(flowables) not in _SeqTypes:
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   337
			self._flowables = [flowables]
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   338
		else:
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   339
			self._flowables = flowables
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   340
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   341
	def __repr__(self):
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   342
		f = self._flowables
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   343
		L = map(repr,f)
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   344
		import string
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   345
		L = "\n"+string.join(L, "\n")
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   346
		L = string.replace(L, "\n", "\n  ")
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   347
		return "KeepTogether(%s) # end KeepTogether" % L
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   348
367
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   349
	def wrap(self, aW, aH):
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   350
		W = 0
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   351
		H = 0
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   352
		F = self._flowables
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   353
		for f in F:
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   354
			w,h = f.wrap(aW,0xfffffff)
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   355
			if f is not F[0]: h = h + f.getSpaceBefore()
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   356
			if f is not F[-1]: h = h + f.getSpaceAfter()
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   357
			W = max(W,w)
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   358
			H = H+h
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   359
		self._CPage = H>aH
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   360
		return W, 0xffffff	# force a split
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   361
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   362
	def split(self, aW, aH):
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   363
		S = self._CPage and [CondPageBreak(aH+1)] or []
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   364
		for f in self._flowables: S.append(f)
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   365
		return S
ca1adb0294f0 Added KeepTogether
rgbecker
parents: 307
diff changeset
   366
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   367
class Macro(Flowable):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   368
	"""This is not actually drawn (i.e. it has zero height)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   369
	but is executed when it would fit in the frame.  Allows direct
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   370
	access to the canvas through the object 'canvas'"""
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   371
	def __init__(self, command):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   372
		self.command = command
541
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   373
	def __repr__(self):
33de80b3655c added __repr__s and enhanced exception messages for debugging
aaron_watters
parents: 512
diff changeset
   374
		return "Macro(%s)" % repr(self.command)
253
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   375
	def wrap(self, availWidth, availHeight):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   376
		return (0,0)
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   377
	def draw(self):
cfcf8d555a2c Platypus re-organisation
rgbecker
parents:
diff changeset
   378
		exec self.command in globals(), {'canvas':self.canv}