187 lines
8.5 KiB
Python
187 lines
8.5 KiB
Python
|
from reportlab.lib.colors import Color, white, black
|
||
|
from reportlab.graphics.charts.textlabels import Label
|
||
|
from reportlab.graphics.shapes import Polygon, Line, Circle, String, Drawing, PolyLine, Group, Rect
|
||
|
from reportlab.graphics.widgetbase import Widget, TypedPropertyCollection
|
||
|
from reportlab.lib.attrmap import *
|
||
|
from reportlab.lib.validators import *
|
||
|
from reportlab.lib.units import cm
|
||
|
from reportlab.pdfbase.pdfmetrics import stringWidth, getFont
|
||
|
from reportlab.graphics.widgets.grids import ShadedRect, Grid
|
||
|
|
||
|
class SlideBox(Widget):
|
||
|
"""Returns a slidebox widget"""
|
||
|
_attrMap = AttrMap(
|
||
|
labelFontName = AttrMapValue(isString, desc="Name of font used for the labels"),
|
||
|
labelFontSize = AttrMapValue(isNumber, desc="Size of font used for the labels"),
|
||
|
labelStrokeColor = AttrMapValue(isColorOrNone, desc="Colour for for number outlines"),
|
||
|
labelFillColor = AttrMapValue(isColorOrNone, desc="Colour for number insides"),
|
||
|
startColor = AttrMapValue(isColor, desc='Color of first box'),
|
||
|
endColor = AttrMapValue(isColor, desc='Color of last box'),
|
||
|
numberOfBoxes = AttrMapValue(isInt, desc='How many boxes there are'),
|
||
|
trianglePosition = AttrMapValue(isInt, desc='Which box is highlighted by the triangles'),
|
||
|
triangleHeight = AttrMapValue(isNumber, desc="Height of indicator triangles"),
|
||
|
triangleWidth = AttrMapValue(isNumber, desc="Width of indicator triangles"),
|
||
|
triangleFillColor = AttrMapValue(isColor, desc="Colour of indicator triangles"),
|
||
|
triangleStrokeColor = AttrMapValue(isColorOrNone, desc="Colour of indicator triangle outline"),
|
||
|
triangleStrokeWidth = AttrMapValue(isNumber, desc="Colour of indicator triangle outline"),
|
||
|
boxHeight = AttrMapValue(isNumber, desc="Height of the boxes"),
|
||
|
boxWidth = AttrMapValue(isNumber, desc="Width of the boxes"),
|
||
|
boxSpacing = AttrMapValue(isNumber, desc="Space between the boxes"),
|
||
|
boxOutlineColor = AttrMapValue(isColorOrNone, desc="Colour used to outline the boxes (if any)"),
|
||
|
boxOutlineWidth = AttrMapValue(isNumberOrNone, desc="Width of the box outline (if any)"),
|
||
|
leftPadding = AttrMapValue(isNumber, desc='Padding on left of drawing'),
|
||
|
rightPadding = AttrMapValue(isNumber, desc='Padding on right of drawing'),
|
||
|
topPadding = AttrMapValue(isNumber, desc='Padding at top of drawing'),
|
||
|
bottomPadding = AttrMapValue(isNumber, desc='Padding at bottom of drawing'),
|
||
|
background = AttrMapValue(isColorOrNone, desc='Colour of the background to the drawing (if any)'),
|
||
|
sourceLabelText = AttrMapValue(isNoneOrString, desc="Text used for the 'source' label (can be empty)"),
|
||
|
sourceLabelOffset = AttrMapValue(isNumber, desc='Padding at bottom of drawing'),
|
||
|
sourceLabelFontName = AttrMapValue(isString, desc="Name of font used for the 'source' label"),
|
||
|
sourceLabelFontSize = AttrMapValue(isNumber, desc="Font size for the 'source' label"),
|
||
|
sourceLabelFillColor = AttrMapValue(isColorOrNone, desc="Colour ink for the 'source' label (bottom right)"),
|
||
|
)
|
||
|
|
||
|
def __init__(self):
|
||
|
self.labelFontName = "Helvetica-Bold"
|
||
|
self.labelFontSize = 10
|
||
|
self.labelStrokeColor = black
|
||
|
self.labelFillColor = white
|
||
|
self.startColor = colors.Color(232/255.0,224/255.0,119/255.0)
|
||
|
self.endColor = colors.Color(25/255.0,77/255.0,135/255.0)
|
||
|
self.numberOfBoxes = 7
|
||
|
self.trianglePosition = 7
|
||
|
self.triangleHeight = 0.12*cm
|
||
|
self.triangleWidth = 0.38*cm
|
||
|
self.triangleFillColor = white
|
||
|
self.triangleStrokeColor = black
|
||
|
self.triangleStrokeWidth = 0.58
|
||
|
self.boxHeight = 0.55*cm
|
||
|
self.boxWidth = 0.73*cm
|
||
|
self.boxSpacing = 0.075*cm
|
||
|
self.boxOutlineColor = black
|
||
|
self.boxOutlineWidth = 0.58
|
||
|
self.leftPadding=5
|
||
|
self.rightPadding=5
|
||
|
self.topPadding=5
|
||
|
self.bottomPadding=5
|
||
|
self.background=None
|
||
|
self.sourceLabelText = "Source: ReportLab"
|
||
|
self.sourceLabelOffset = 0.2*cm
|
||
|
self.sourceLabelFontName = "Helvetica-Oblique"
|
||
|
self.sourceLabelFontSize = 6
|
||
|
self.sourceLabelFillColor = black
|
||
|
|
||
|
def _getDrawingDimensions(self):
|
||
|
tx=(self.numberOfBoxes*self.boxWidth)
|
||
|
if self.numberOfBoxes>1: tx=tx+((self.numberOfBoxes-1)*self.boxSpacing)
|
||
|
tx=tx+self.leftPadding+self.rightPadding
|
||
|
ty=self.boxHeight+self.triangleHeight
|
||
|
ty=ty+self.topPadding+self.bottomPadding+self.sourceLabelOffset+self.sourceLabelFontSize
|
||
|
return (tx,ty)
|
||
|
|
||
|
def _getColors(self):
|
||
|
# for calculating intermediate colors...
|
||
|
numShades = self.numberOfBoxes+1
|
||
|
fillColorStart = self.startColor
|
||
|
fillColorEnd = self.endColor
|
||
|
colorsList =[]
|
||
|
|
||
|
for i in range(0,numShades):
|
||
|
colorsList.append(colors.linearlyInterpolatedColor(fillColorStart, fillColorEnd, 0, numShades-1, i))
|
||
|
return colorsList
|
||
|
|
||
|
def demo(self,drawing=None):
|
||
|
from reportlab.lib import colors
|
||
|
if not drawing:
|
||
|
tx,ty=self._getDrawingDimensions()
|
||
|
drawing = Drawing(tx,ty)
|
||
|
drawing.add(self.draw())
|
||
|
return drawing
|
||
|
|
||
|
def draw(self):
|
||
|
g = Group()
|
||
|
ys = self.bottomPadding+(self.triangleHeight/2)+self.sourceLabelOffset+self.sourceLabelFontSize
|
||
|
if self.background:
|
||
|
x,y = self._getDrawingDimensions()
|
||
|
g.add(Rect(-self.leftPadding,-ys,x,y,
|
||
|
strokeColor=None,
|
||
|
strokeWidth=0,
|
||
|
fillColor=self.background))
|
||
|
|
||
|
ascent=getFont(self.labelFontName).face.ascent/1000.
|
||
|
if ascent==0: ascent=0.718 # default (from helvetica)
|
||
|
ascent=ascent*self.labelFontSize # normalize
|
||
|
|
||
|
colorsList = self._getColors()
|
||
|
|
||
|
# Draw the boxes - now uses ShadedRect from grids
|
||
|
x=0
|
||
|
for f in range (0,self.numberOfBoxes):
|
||
|
sr=ShadedRect()
|
||
|
sr.x=x
|
||
|
sr.y=0
|
||
|
sr.width=self.boxWidth
|
||
|
sr.height=self.boxHeight
|
||
|
sr.orientation = 'vertical'
|
||
|
sr.numShades = 30
|
||
|
sr.fillColorStart = colorsList[f]
|
||
|
sr.fillColorEnd = colorsList[f+1]
|
||
|
sr.strokeColor = None
|
||
|
sr.strokeWidth = 0
|
||
|
|
||
|
g.add(sr)
|
||
|
|
||
|
g.add(Rect(x,0,self.boxWidth,self.boxHeight,
|
||
|
strokeColor=self.boxOutlineColor,
|
||
|
strokeWidth=self.boxOutlineWidth,
|
||
|
fillColor=None))
|
||
|
|
||
|
g.add(String(x+self.boxWidth/2.,(self.boxHeight-ascent)/2.,
|
||
|
text = str(f+1),
|
||
|
fillColor = self.labelFillColor,
|
||
|
strokeColor=self.labelStrokeColor,
|
||
|
textAnchor = 'middle',
|
||
|
fontName = self.labelFontName,
|
||
|
fontSize = self.labelFontSize))
|
||
|
x=x+self.boxWidth+self.boxSpacing
|
||
|
|
||
|
#do triangles
|
||
|
xt = (self.trianglePosition*self.boxWidth)
|
||
|
if self.trianglePosition>1:
|
||
|
xt = xt+(self.trianglePosition-1)*self.boxSpacing
|
||
|
xt = xt-(self.boxWidth/2)
|
||
|
g.add(Polygon(
|
||
|
strokeColor = self.triangleStrokeColor,
|
||
|
strokeWidth = self.triangleStrokeWidth,
|
||
|
fillColor = self.triangleFillColor,
|
||
|
points=[xt,self.boxHeight-(self.triangleHeight/2),
|
||
|
xt-(self.triangleWidth/2),self.boxHeight+(self.triangleHeight/2),
|
||
|
xt+(self.triangleWidth/2),self.boxHeight+(self.triangleHeight/2),
|
||
|
xt,self.boxHeight-(self.triangleHeight/2)]))
|
||
|
g.add(Polygon(
|
||
|
strokeColor = self.triangleStrokeColor,
|
||
|
strokeWidth = self.triangleStrokeWidth,
|
||
|
fillColor = self.triangleFillColor,
|
||
|
points=[xt,0+(self.triangleHeight/2),
|
||
|
xt-(self.triangleWidth/2),0-(self.triangleHeight/2),
|
||
|
xt+(self.triangleWidth/2),0-(self.triangleHeight/2),
|
||
|
xt,0+(self.triangleHeight/2)]))
|
||
|
|
||
|
#source label
|
||
|
if self.sourceLabelText != None:
|
||
|
g.add(String(x-self.boxSpacing,0-(self.triangleHeight/2)-self.sourceLabelOffset-(self.sourceLabelFontSize),
|
||
|
text = self.sourceLabelText,
|
||
|
fillColor = self.sourceLabelFillColor,
|
||
|
textAnchor = 'end',
|
||
|
fontName = self.sourceLabelFontName,
|
||
|
fontSize = self.sourceLabelFontSize))
|
||
|
|
||
|
g.shift(self.leftPadding, ys)
|
||
|
|
||
|
return g
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
d = SlideBox()
|
||
|
d.demo().save(fnRoot="slidebox")
|