Files
PyRIGS/z3c/rml/canvas.py
2014-12-07 17:32:25 +00:00

1013 lines
31 KiB
Python

##############################################################################
#
# Copyright (c) 2007 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Page Drawing Related Element Processing
"""
import zope.interface
import reportlab.pdfgen.canvas
from z3c.rml import attr, directive, interfaces, occurence, stylesheet
from z3c.rml import chart, flowable, form, page, special
class IShape(interfaces.IRMLDirectiveSignature):
"""A shape to be drawn on the canvas."""
x = attr.Measurement(
title=u'X-Coordinate',
description=(u'The X-coordinate of the lower-left position of the '
u'shape.'),
required=True)
y = attr.Measurement(
title=u'Y-Coordinate',
description=(u'The Y-coordinate of the lower-left position of the '
u'shape.'),
required=True)
fill = attr.Boolean(
title=u'Fill',
description=u'A flag to specify whether the shape should be filled.',
required=False)
stroke = attr.Boolean(
title=u'Stroke',
description=(u"A flag to specify whether the shape's outline should "
u"be drawn."),
required=False)
class CanvasRMLDirective(directive.RMLDirective):
callable = None
attrMapping = None
def process(self):
kwargs = dict(self.getAttributeValues(attrMapping=self.attrMapping))
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
getattr(canvas, self.callable)(**kwargs)
class ISaveState(interfaces.IRMLDirectiveSignature):
"""Saves the current canvas state."""
class SaveState(CanvasRMLDirective):
signature = ISaveState
callable = 'saveState'
class IRestoreState(interfaces.IRMLDirectiveSignature):
"""Saves the current canvas state."""
class RestoreState(CanvasRMLDirective):
signature = IRestoreState
callable = 'restoreState'
class IDrawString(interfaces.IRMLDirectiveSignature):
"""Draws a simple string (left aligned) onto the canvas at the specified
location."""
x = attr.Measurement(
title=u'X-Coordinate',
description=(u'The X-coordinate of the lower-left position of the '
u'string.'),
required=True)
y = attr.Measurement(
title=u'Y-Coordinate',
description=(u'The Y-coordinate of the lower-left position of the '
u'string.'),
required=True)
text = attr.RawXMLContent(
title=u'Text',
description=(u'The string/text that is put onto the canvas.'),
required=True)
class DrawString(CanvasRMLDirective, special.TextFlowables):
signature = IDrawString
callable = 'drawString'
def process(self):
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
kwargs = dict(self.getAttributeValues(attrMapping=self.attrMapping))
kwargs['text'] = self._getText(self.element, canvas).strip()
getattr(canvas, self.callable)(**kwargs)
class IDrawRightString(IDrawString):
"""Draws a simple string (right aligned) onto the canvas at the specified
location."""
class DrawRightString(DrawString):
signature = IDrawRightString
callable = 'drawRightString'
class IDrawCenteredString(IDrawString):
"""Draws a simple string (centered aligned) onto the canvas at the specified
location."""
class DrawCenteredString(DrawString):
signature = IDrawCenteredString
callable = 'drawCentredString'
class IDrawAlignedString(IDrawString):
"""Draws a simple string (aligned to the pivot character) onto the canvas
at the specified location."""
pivotChar = attr.Text(
title=u'Text',
description=(u'The string/text that is put onto the canvas.'),
min_length=1,
max_length=1,
default=u'.',
required=True)
class DrawAlignedString(DrawString):
signature = IDrawAlignedString
callable = 'drawAlignedString'
class IEllipse(IShape):
"""Draws an ellipse on the canvas."""
width = attr.Measurement(
title=u'Width',
description=u'The width of the ellipse.',
required=True)
height = attr.Measurement(
title=u'Height',
description=u'The height of the ellipse.',
required=True)
class Ellipse(CanvasRMLDirective):
signature = IEllipse
callable = 'ellipse'
attrMapping = {'x': 'x1', 'y': 'y1'}
def process(self):
kwargs = dict(self.getAttributeValues(attrMapping=self.attrMapping))
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
# Convert width and height to end locations
kwargs['x2'] = kwargs['x1'] + kwargs['width']
del kwargs['width']
kwargs['y2'] = kwargs['y1'] + kwargs['height']
del kwargs['height']
getattr(canvas, self.callable)(**kwargs)
class ICircle(IShape):
"""Draws a circle on the canvas."""
radius = attr.Measurement(
title=u'Radius',
description=u'The radius of the circle.',
required=True)
class Circle(CanvasRMLDirective):
signature = ICircle
callable = 'circle'
attrMapping = {'x': 'x_cen', 'y': 'y_cen', 'radius': 'r'}
class IRectangle(IShape):
"""Draws an ellipse on the canvas."""
width = attr.Measurement(
title=u'Width',
description=u'The width of the rectangle.',
required=True)
height = attr.Measurement(
title=u'Height',
description=u'The height of the rectangle.',
required=True)
round = attr.Measurement(
title=u'Corner Radius',
description=u'The radius of the rounded corners.',
required=False)
href = attr.Text(
title=u'Link URL',
description=u'When specified, the rectangle becomes a link to that URL.',
required=False)
destination = attr.Text(
title=u'Link Destination',
description=(u'When specified, the rectangle becomes a link to that '
u'destination.'),
required=False)
class Rectangle(CanvasRMLDirective):
signature = IRectangle
callable = 'rect'
attrMapping = {'round': 'radius'}
def process(self):
if 'round' in self.element.keys():
self.callable = 'roundRect'
kwargs = dict(self.getAttributeValues(attrMapping=self.attrMapping))
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
# Create a link
url = kwargs.pop('href', None)
if url:
canvas.linkURL(
url,
(kwargs['x'], kwargs['y'],
kwargs['x']+kwargs['width'], kwargs['y']+kwargs['height']))
dest = kwargs.pop('destination', None)
if dest:
canvas.linkRect(
'', dest,
(kwargs['x'], kwargs['y'],
kwargs['x']+kwargs['width'], kwargs['y']+kwargs['height']))
# Render the rectangle
getattr(canvas, self.callable)(**kwargs)
class IGrid(interfaces.IRMLDirectiveSignature):
"""A shape to be drawn on the canvas."""
xs = attr.Sequence(
title=u'X-Coordinates',
description=(u'A sequence x-coordinates that represent the vertical '
u'line positions.'),
value_type=attr.Measurement(),
required=True)
ys = attr.Sequence(
title=u'Y-Coordinates',
description=(u'A sequence y-coordinates that represent the horizontal '
u'line positions.'),
value_type=attr.Measurement(),
required=True)
class Grid(CanvasRMLDirective):
signature = IGrid
callable = 'grid'
attrMapping = {'xs': 'xlist', 'ys': 'ylist'}
class ILines(interfaces.IRMLDirectiveSignature):
"""A path of connected lines drawn on the canvas."""
linelist = attr.TextNodeGrid(
title=u'Line List',
description=(u'A list of lines coordinates to draw.'),
value_type=attr.Measurement(),
columns=4,
required=True)
class Lines(CanvasRMLDirective):
signature = ILines
callable = 'lines'
class ICurves(interfaces.IRMLDirectiveSignature):
"""A path of connected bezier curves drawn on the canvas."""
curvelist = attr.TextNodeGrid(
title=u'Curve List',
description=(u'A list of curve coordinates to draw.'),
value_type=attr.Measurement(),
columns=8,
required=True)
class Curves(CanvasRMLDirective):
signature = ICurves
callable = 'bezier'
def process(self):
argset = self.getAttributeValues(valuesOnly=True)[0]
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
for args in argset:
getattr(canvas, self.callable)(*args)
class IImage(interfaces.IRMLDirectiveSignature):
"""Draws an external image on the canvas."""
file = attr.Image(
title=u'File',
description=(u'Reference to the external file of the iamge.'),
required=True)
x = attr.Measurement(
title=u'X-Coordinate',
description=(u'The X-coordinate of the lower-left position of the '
u'shape.'),
required=True)
y = attr.Measurement(
title=u'Y-Coordinate',
description=(u'The Y-coordinate of the lower-left position of the '
u'shape.'),
required=True)
width = attr.Measurement(
title=u'Width',
description=u'The width of the image.',
required=False)
height = attr.Measurement(
title=u'Height',
description=u'The height of the image.',
required=False)
showBoundary = attr.Boolean(
title=u'Show Boundary',
description=(u'A flag determining whether a border should be drawn '
u'around the image.'),
default=False,
required=False)
preserveAspectRatio = attr.Boolean(
title=u'Preserve Aspect Ratio',
description=(u"A flag determining whether the image's aspect ration "
u"should be conserved under any circumstances."),
default=False,
required=False)
class Image(CanvasRMLDirective):
signature = IImage
callable = 'drawImage'
attrMapping = {'file': 'image'}
def process(self):
kwargs = dict(self.getAttributeValues(attrMapping=self.attrMapping))
preserve = kwargs.pop('preserveAspectRatio')
show = kwargs.pop('showBoundary')
if preserve:
imgX, imgY = kwargs['image'].getSize()
# Scale image correctly, if width and/or height were specified
if 'width' in kwargs and 'height' not in kwargs:
kwargs['height'] = imgY * kwargs['width'] / imgX
elif 'height' in kwargs and 'width' not in kwargs:
kwargs['width'] = imgX * kwargs['height'] / imgY
elif 'width' in kwargs and 'height' in kwargs:
if float(kwargs['width'])/kwargs['height'] > float(imgX)/imgY:
kwargs['width'] = imgX * kwargs['height'] / imgY
else:
kwargs['height'] = imgY * kwargs['width'] / imgX
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
getattr(canvas, self.callable)(**kwargs)
if show:
width = kwargs.get('width', kwargs['image'].getSize()[0])
height = kwargs.get('height', kwargs['image'].getSize()[1])
canvas.rect(kwargs['x'], kwargs['y'], width, height)
class IPlace(interfaces.IRMLDirectiveSignature):
"""Draws a set of flowables on the canvas within a given region."""
x = attr.Measurement(
title=u'X-Coordinate',
description=(u'The X-coordinate of the lower-left position of the '
u'place.'),
required=True)
y = attr.Measurement(
title=u'Y-Coordinate',
description=(u'The Y-coordinate of the lower-left position of the '
u'place.'),
required=True)
width = attr.Measurement(
title=u'Width',
description=u'The width of the place.',
required=False)
height = attr.Measurement(
title=u'Height',
description=u'The height of the place.',
required=False)
class Place(CanvasRMLDirective):
signature = IPlace
def process(self):
x, y, width, height = self.getAttributeValues(
select=('x', 'y', 'width', 'height'), valuesOnly=True)
y += height
flows = flowable.Flow(self.element, self.parent)
flows.process()
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
for flow in flows.flow:
flowWidth, flowHeight = flow.wrap(width, height)
if flowWidth <= width and flowHeight <= height:
y -= flowHeight
flow.drawOn(canvas, x, y)
height -= flowHeight
else:
raise ValueError("Not enough space")
class IParam(interfaces.IRMLDirectiveSignature):
"""Sets one paramter for the text annotation."""
name = attr.String(
title=u'Name',
description=u'The name of the paramter.',
required=True)
value = attr.TextNode(
title=u'Value',
description=(u'The parameter value.'),
required=True)
class Param(directive.RMLDirective):
signature = IParam
def process(self):
args = dict(self.getAttributeValues())
self.parent.params[args['name']] = args['value']
class ITextAnnotation(interfaces.IRMLDirectiveSignature):
"""Writes a low-level text annotation into the PDF."""
occurence.containing(
occurence.ZeroOrMore('param', IParam))
contents = attr.FirstLevelTextNode(
title=u'Contents',
description=u'The PDF commands that are inserted as annotation.',
required=True)
class TextAnnotation(CanvasRMLDirective):
signature = ITextAnnotation
factories = {'param': Param}
paramTypes = {'escape': attr.Integer()}
def process(self):
contents = self.getAttributeValues(valuesOnly=True)[0]
self.params = {}
self.processSubDirectives()
for name, type in self.paramTypes.items():
if name in self.params:
bound = type.bind(self)
self.params[name] = bound.fromUnicode(self.params[name])
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
canvas.textAnnotation(contents, **self.params)
class IMoveTo(interfaces.IRMLDirectiveSignature):
"""Move the path cursor to the specified location."""
position = attr.TextNodeSequence(
title=u'Position',
description=u'Position to which the path pointer is moved to.',
value_type=attr.Measurement(),
min_length=2,
max_length=2,
required=True)
class MoveTo(directive.RMLDirective):
signature = IMoveTo
def process(self):
args = self.getAttributeValues(valuesOnly=True)
self.parent.path.moveTo(*args[0])
class ICurveTo(interfaces.IRMLDirectiveSignature):
"""Create a bezier curve from the current location to the specified one."""
curvelist = attr.TextNodeGrid(
title=u'Curve Specification',
description=u'Describes the end position and the curve properties.',
value_type=attr.Measurement(),
columns=6,
required=True)
class CurveTo(directive.RMLDirective):
signature = ICurveTo
def process(self):
argset = self.getAttributeValues(valuesOnly=True)[0]
for args in argset:
self.parent.path.curveTo(*args)
class ICurvesTo(ICurveTo):
pass
directive.DeprecatedDirective(
ICurvesTo,
'Available for ReportLab RML compatibility. Please use the "curveto" '
'directive instead.')
class IPath(IShape):
"""Create a line path."""
occurence.containing(
occurence.ZeroOrMore('moveto', IMoveTo),
occurence.ZeroOrMore('curveto', ICurveTo),
occurence.ZeroOrMore('curvesto', ICurvesTo),
)
points = attr.TextNodeGrid(
title=u'Points',
description=(u'A list of coordinate points that define th path.'),
value_type=attr.Measurement(),
columns=2,
required=True)
close = attr.Boolean(
title=u'Close Path',
description=(u"A flag specifying whether the path should be closed."),
default=False,
required=False)
clip = attr.Boolean(
title=u'Clip Path',
description=(u"A flag specifying whether the path should clip "
u"overlapping elements."),
default=False,
required=False)
class Path(CanvasRMLDirective):
signature = IPath
factories = {
'moveto': MoveTo,
'curveto': CurveTo,
'curvesto': CurveTo
}
def processPoints(self, text):
if text.strip() == '':
return
bound = self.signature['points'].bind(self)
for coords in bound.fromUnicode(text):
self.path.lineTo(*coords)
def process(self):
kwargs = dict(self.getAttributeValues(ignore=('points',)))
# Start the path and set the cursor to the start location.
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
self.path = canvas.beginPath()
self.path.moveTo(kwargs.pop('x'), kwargs.pop('y'))
# Process the text before the first sub-directive.
if self.element.text is not None:
self.processPoints(self.element.text)
# Handle each sub-directive.
for directive in self.element.getchildren():
if directive.tag in self.factories:
self.factories[directive.tag](directive, self).process()
# If there is more text after sub-directive, process it.
if directive.tail is not None:
self.processPoints(directive.tail)
if kwargs.pop('close', False):
self.path.close()
if kwargs.pop('clip', False):
canvas.clipPath(self.path, **kwargs)
else:
canvas.drawPath(self.path, **kwargs)
class IFill(interfaces.IRMLDirectiveSignature):
"""Set the fill color."""
color = attr.Color(
title=u'Color',
description=(u'The color value to be set.'),
required=True)
class Fill(CanvasRMLDirective):
signature = IFill
callable = 'setFillColor'
attrMapping = {'color': 'aColor'}
class IStroke(interfaces.IRMLDirectiveSignature):
"""Set the stroke/line color."""
color = attr.Color(
title=u'Color',
description=(u'The color value to be set.'),
required=True)
class Stroke(CanvasRMLDirective):
signature = IStroke
callable = 'setStrokeColor'
attrMapping = {'color': 'aColor'}
class ISetFont(interfaces.IRMLDirectiveSignature):
"""Set the font name and/or size."""
name = attr.String(
title=u'Font Name',
description=(u'The name of the font as it was registered.'),
required=True)
size = attr.Measurement(
title=u'Size',
description=(u'The font size.'),
required=True)
leading = attr.Measurement(
title=u'Leading',
description=(u'The font leading.'),
required=False)
class SetFont(CanvasRMLDirective):
signature = ISetFont
callable = 'setFont'
attrMapping = {'name': 'psfontname'}
class ISetFontSize(interfaces.IRMLDirectiveSignature):
"""Set the font size."""
size = attr.Measurement(
title=u'Size',
description=(u'The font size.'),
required=True)
leading = attr.Measurement(
title=u'Leading',
description=(u'The font leading.'),
required=False)
class SetFontSize(CanvasRMLDirective):
signature = ISetFontSize
callable = 'setFontSize'
class IScale(interfaces.IRMLDirectiveSignature):
"""Scale the drawing using x and y scaling factors."""
sx = attr.Float(
title=u'X-Scaling-Factor',
description=(u'The scaling factor applied on x-coordinates.'),
default=1,
required=False)
sy = attr.Float(
title=u'Y-Scaling-Factor',
description=(u'The scaling factor applied on y-coordinates.'),
default=1,
required=False)
class Scale(CanvasRMLDirective):
signature = IScale
callable = 'scale'
attrMapping = {'sx': 'x', 'sy': 'y'}
class ITranslate(interfaces.IRMLDirectiveSignature):
"""Translate the drawing coordinates by the specified x and y offset."""
dx = attr.Measurement(
title=u'X-Offset',
description=(u'The amount to move the drawing to the right.'),
required=True)
dy = attr.Measurement(
title=u'Y-Offset',
description=(u'The amount to move the drawing upward.'),
required=True)
class Translate(CanvasRMLDirective):
signature = ITranslate
callable = 'translate'
class IRotate(interfaces.IRMLDirectiveSignature):
"""Rotate the drawing counterclockwise."""
degrees = attr.Measurement(
title=u'Angle',
description=(u'The angle in degrees.'),
required=True)
class Rotate(CanvasRMLDirective):
signature = IRotate
callable = 'rotate'
attrMapping = {'degrees': 'theta'}
class ISkew(interfaces.IRMLDirectiveSignature):
"""Skew the drawing."""
alpha = attr.Measurement(
title=u'Alpha',
description=(u'The amount to skew the drawing in the horizontal.'),
required=True)
beta = attr.Measurement(
title=u'Beta',
description=(u'The amount to skew the drawing in the vertical.'),
required=True)
class Skew(CanvasRMLDirective):
signature = ISkew
callable = 'skew'
class ITransform(interfaces.IRMLDirectiveSignature):
"""A full 2-D matrix transformation"""
matrix = attr.TextNodeSequence(
title=u'Matrix',
description=u'The transformation matrix.',
value_type=attr.Float(),
min_length=6,
max_length=6,
required=True)
class Transform(CanvasRMLDirective):
signature = ITransform
def process(self):
args = self.getAttributeValues(valuesOnly=True)
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
canvas.transform(*args[0])
class ILineMode(interfaces.IRMLDirectiveSignature):
"""Set the line mode for the following graphics elements."""
width = attr.Measurement(
title=u'Width',
description=(u'The line width.'),
required=False)
dash = attr.Sequence(
title=u'Dash-Pattern',
description=(u'The dash-pattern of a line.'),
value_type=attr.Measurement(),
required=False)
miterLimit = attr.Measurement(
title=u'Miter Limit',
description=(u'The ???.'),
required=False)
join = attr.Choice(
title=u'Join',
description=u'The way lines are joined together.',
choices=interfaces.JOIN_CHOICES,
required=False)
cap = attr.Choice(
title=u'Cap',
description=u'The cap is the desciption of how the line-endings look.',
choices=interfaces.CAP_CHOICES,
required=False)
class LineMode(CanvasRMLDirective):
signature = ILineMode
def process(self):
kw = dict(self.getAttributeValues())
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
if 'width' in kw:
canvas.setLineWidth(kw['width'])
if 'join' in kw:
canvas.setLineJoin(kw['join'])
if 'cap' in kw:
canvas.setLineCap(kw['cap'])
if 'miterLimit' in kw:
canvas.setMiterLimit(kw['miterLimit'])
if 'dash' in kw:
canvas.setDash(kw['dash'])
class IBookmark(interfaces.IRMLDirectiveSignature):
"""
This creates a bookmark to the current page which can be referred to with
the given key elsewhere. (Used inside a page drawing.)
"""
name = attr.Text(
title=u'Name',
description=u'The name of the bookmark.',
required=True)
fit = attr.Choice(
title=u'Fit',
description=u'The Fit Type.',
choices=('XYZ', 'Fit', 'FitH', 'FitV', 'FitR'),
required=False)
zoom = attr.Float(
title=u'Zoom',
description=u'The zoom level when clicking on the bookmark.',
required=False)
x = attr.Measurement(
title=u'X-Position',
description=u'The x-position.',
required=False)
y = attr.Measurement(
title=u'Y-Position',
description=u'The y-position.',
required=False)
class Bookmark(CanvasRMLDirective):
signature = IBookmark
def process(self):
args = dict(self.getAttributeValues())
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
args['left'], args['top'] = canvas.absolutePosition(args['x'], args['y'])
canvas.bookmarkPage(**args)
class IPlugInGraphic(interfaces.IRMLDirectiveSignature):
"""Inserts a custom graphic developed in Python."""
module = attr.String(
title=u'Module',
description=u'The Python module in which the flowable is located.',
required=True)
function = attr.String(
title=u'Function',
description=(u'The name of the factory function within the module '
u'that returns the custom flowable.'),
required=True)
params = attr.TextNode(
title=u'Parameters',
description=(u'A list of parameters encoded as a long string.'),
required=False)
class PlugInGraphic(CanvasRMLDirective):
signature = IPlugInGraphic
def process(self):
modulePath, functionName, params = self.getAttributeValues(
valuesOnly=True)
module = __import__(modulePath, {}, {}, [modulePath])
function = getattr(module, functionName)
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
function(canvas, params)
class IDrawing(interfaces.IRMLDirectiveSignature):
"""A container directive for all directives that draw directly on the
cnavas."""
occurence.containing(
# State Manipulation
occurence.ZeroOrMore('saveState', ISaveState),
occurence.ZeroOrMore('restoreState', IRestoreState),
# String Drawing
occurence.ZeroOrMore('drawString', IDrawString),
occurence.ZeroOrMore('drawRightString', IDrawRightString),
occurence.ZeroOrMore('drawCenteredString', IDrawCenteredString),
occurence.ZeroOrMore('drawCentredString', IDrawCenteredString),
occurence.ZeroOrMore('drawAlignedString', IDrawAlignedString),
# Drawing Operations
occurence.ZeroOrMore('ellipse', IEllipse),
occurence.ZeroOrMore('circle', ICircle),
occurence.ZeroOrMore('rect', IRectangle),
occurence.ZeroOrMore('grid', IGrid),
occurence.ZeroOrMore('lines', ILines),
occurence.ZeroOrMore('curves', ICurves),
occurence.ZeroOrMore('image', IImage),
occurence.ZeroOrMore('place', IPlace),
occurence.ZeroOrMore('textAnnotation', ITextAnnotation),
occurence.ZeroOrMore('path', IPath),
# State Change Operations
occurence.ZeroOrMore('fill', IFill),
occurence.ZeroOrMore('stroke', IStroke),
occurence.ZeroOrMore('setFont', ISetFont),
occurence.ZeroOrMore('setFontSize', ISetFontSize),
occurence.ZeroOrMore('scale', IScale),
occurence.ZeroOrMore('translate', ITranslate),
occurence.ZeroOrMore('rotate', IRotate),
occurence.ZeroOrMore('skew', ISkew),
occurence.ZeroOrMore('transform', ITransform),
occurence.ZeroOrMore('lineMode', ILineMode),
# Form Field Elements
occurence.ZeroOrMore('barCode', form.IBarCode),
occurence.ZeroOrMore('textField', form.ITextField),
occurence.ZeroOrMore('buttonField', form.IButtonField),
occurence.ZeroOrMore('selectField', form.ISelectField),
# Charts
occurence.ZeroOrMore('barChart', chart.IBarChart),
occurence.ZeroOrMore('barChart3D', chart.IBarChart3D),
occurence.ZeroOrMore('linePlot', chart.ILinePlot),
occurence.ZeroOrMore('linePlot3D', chart.ILinePlot3D),
occurence.ZeroOrMore('pieChart', chart.IPieChart),
occurence.ZeroOrMore('pieChart3D', chart.IPieChart3D),
occurence.ZeroOrMore('spiderChart', chart.ISpiderChart),
# Misc
occurence.ZeroOrMore('bookmark', IBookmark),
occurence.ZeroOrMore('plugInGraphic', IPlugInGraphic),
)
class Drawing(directive.RMLDirective):
signature = IDrawing
factories = {
# State Management
'saveState': SaveState,
'restoreState': RestoreState,
# Drawing Strings
'drawString': DrawString,
'drawRightString': DrawRightString,
'drawCenteredString': DrawCenteredString,
'drawCentredString': DrawCenteredString,
'drawAlignedString': DrawAlignedString,
# Drawing Operations
'ellipse': Ellipse,
'circle': Circle,
'rect': Rectangle,
'grid': Grid,
'lines': Lines,
'curves': Curves,
'image': Image,
'place': Place,
'textAnnotation': TextAnnotation,
'path': Path,
# Form Field Elements
'barCode': form.BarCode,
'textField': form.TextField,
'buttonField': form.ButtonField,
'selectField': form.SelectField,
# State Change Operations
'fill': Fill,
'stroke': Stroke,
'setFont': SetFont,
'setFontSize': SetFontSize,
'scale': Scale,
'translate': Translate,
'rotate': Rotate,
'skew': Skew,
'transform': Transform,
'lineMode': LineMode,
# Charts
'barChart': chart.BarChart,
'barChart3D': chart.BarChart3D,
'linePlot': chart.LinePlot,
'linePlot3D': chart.LinePlot3D,
'pieChart': chart.PieChart,
'pieChart3D': chart.PieChart3D,
'spiderChart': chart.SpiderChart,
# Misc
'bookmark': Bookmark,
'plugInGraphic': PlugInGraphic,
}
class IPageDrawing(IDrawing):
"""Draws directly on the content of one page's canvas. Every call of this
directive creates a new page."""
occurence.containing(
#'mergePage': IMergePage,
*IDrawing.getTaggedValue('directives'))
class PageDrawing(Drawing):
signature = IDrawing
factories = Drawing.factories.copy()
factories.update({
'mergePage': page.MergePage
})
def process(self):
super(Drawing, self).process()
canvas = attr.getManager(self, interfaces.ICanvasManager).canvas
canvas.showPage()
class IPageInfo(interfaces.IRMLDirectiveSignature):
"""Set's up page-global settings."""
pageSize = attr.PageSize(
title=u'Page Size',
description=(u'The page size of all pages within this document.'),
required=True)
class PageInfo(CanvasRMLDirective):
signature=IPageInfo
callable = 'setPageSize'
attrMapping = {'pageSize': 'size'}