mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-20 23:12:15 +00:00
Added printing requirements
This commit is contained in:
5
reportlab/graphics/widgets/__init__.py
Normal file
5
reportlab/graphics/widgets/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2012
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/__init__.py
|
||||
__version__=''' $Id$ '''
|
||||
__doc__='''Some non-chart widgets'''
|
||||
304
reportlab/graphics/widgets/eventcal.py
Normal file
304
reportlab/graphics/widgets/eventcal.py
Normal file
@@ -0,0 +1,304 @@
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/eventcal.py
|
||||
# Event Calendar widget
|
||||
# author: Andy Robinson
|
||||
|
||||
__version__=''' $Id$ '''
|
||||
__doc__="""This file is a
|
||||
"""
|
||||
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.validators import *
|
||||
from reportlab.lib.attrmap import *
|
||||
from reportlab.graphics.shapes import Line, Rect, Polygon, Drawing, Group, String, Circle, Wedge
|
||||
from reportlab.graphics.charts.textlabels import Label
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
from reportlab.graphics import renderPDF
|
||||
|
||||
|
||||
|
||||
|
||||
class EventCalendar(Widget):
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.width = 300
|
||||
self.height = 150
|
||||
self.timeColWidth = None # if declared, use it; otherwise auto-size.
|
||||
self.trackRowHeight = 20
|
||||
self.data = [] # list of Event objects
|
||||
self.trackNames = None
|
||||
|
||||
self.startTime = None #displays ALL data on day if not set
|
||||
self.endTime = None # displays ALL data on day if not set
|
||||
self.day = 0
|
||||
|
||||
|
||||
# we will keep any internal geometry variables
|
||||
# here. These are computed by computeSize(),
|
||||
# which is the first thing done when drawing.
|
||||
self._talksVisible = [] # subset of data which will get plotted, cache
|
||||
self._startTime = None
|
||||
self._endTime = None
|
||||
self._trackCount = 0
|
||||
self._colWidths = []
|
||||
self._colLeftEdges = [] # left edge of each column
|
||||
|
||||
def computeSize(self):
|
||||
"Called at start of draw. Sets various column widths"
|
||||
self._talksVisible = self.getRelevantTalks(self.data)
|
||||
self._trackCount = len(self.getAllTracks())
|
||||
self.computeStartAndEndTimes()
|
||||
self._colLeftEdges = [self.x]
|
||||
if self.timeColWidth is None:
|
||||
w = self.width / (1 + self._trackCount)
|
||||
self._colWidths = [w] * (1+ self._trackCount)
|
||||
for i in range(self._trackCount):
|
||||
self._colLeftEdges.append(self._colLeftEdges[-1] + w)
|
||||
else:
|
||||
self._colWidths = [self.timeColWidth]
|
||||
w = (self.width - self.timeColWidth) / self._trackCount
|
||||
for i in range(self._trackCount):
|
||||
self._colWidths.append(w)
|
||||
self._colLeftEdges.append(self._colLeftEdges[-1] + w)
|
||||
|
||||
|
||||
|
||||
def computeStartAndEndTimes(self):
|
||||
"Work out first and last times to display"
|
||||
if self.startTime:
|
||||
self._startTime = self.startTime
|
||||
else:
|
||||
for (title, speaker, trackId, day, start, duration) in self._talksVisible:
|
||||
|
||||
if self._startTime is None: #first one
|
||||
self._startTime = start
|
||||
else:
|
||||
if start < self._startTime:
|
||||
self._startTime = start
|
||||
|
||||
if self.endTime:
|
||||
self._endTime = self.endTime
|
||||
else:
|
||||
for (title, speaker, trackId, day, start, duration) in self._talksVisible:
|
||||
if self._endTime is None: #first one
|
||||
self._endTime = start + duration
|
||||
else:
|
||||
if start + duration > self._endTime:
|
||||
self._endTime = start + duration
|
||||
|
||||
|
||||
|
||||
|
||||
def getAllTracks(self):
|
||||
tracks = []
|
||||
for (title, speaker, trackId, day, hours, duration) in self.data:
|
||||
if trackId is not None:
|
||||
if trackId not in tracks:
|
||||
tracks.append(trackId)
|
||||
tracks.sort()
|
||||
return tracks
|
||||
|
||||
def getRelevantTalks(self, talkList):
|
||||
"Scans for tracks actually used"
|
||||
used = []
|
||||
for talk in talkList:
|
||||
(title, speaker, trackId, day, hours, duration) = talk
|
||||
assert trackId != 0, "trackId must be None or 1,2,3... zero not allowed!"
|
||||
if day == self.day:
|
||||
if (((self.startTime is None) or ((hours + duration) >= self.startTime))
|
||||
and ((self.endTime is None) or (hours <= self.endTime))):
|
||||
used.append(talk)
|
||||
return used
|
||||
|
||||
def scaleTime(self, theTime):
|
||||
"Return y-value corresponding to times given"
|
||||
axisHeight = self.height - self.trackRowHeight
|
||||
# compute fraction between 0 and 1, 0 is at start of period
|
||||
proportionUp = ((theTime - self._startTime) / (self._endTime - self._startTime))
|
||||
y = self.y + axisHeight - (axisHeight * proportionUp)
|
||||
return y
|
||||
|
||||
|
||||
def getTalkRect(self, startTime, duration, trackId, text):
|
||||
"Return shapes for a specific talk"
|
||||
g = Group()
|
||||
y_bottom = self.scaleTime(startTime + duration)
|
||||
y_top = self.scaleTime(startTime)
|
||||
y_height = y_top - y_bottom
|
||||
|
||||
if trackId is None:
|
||||
#spans all columns
|
||||
x = self._colLeftEdges[1]
|
||||
width = self.width - self._colWidths[0]
|
||||
else:
|
||||
#trackId is 1-based and these arrays have the margin info in column
|
||||
#zero, so no need to add 1
|
||||
x = self._colLeftEdges[trackId]
|
||||
width = self._colWidths[trackId]
|
||||
|
||||
lab = Label()
|
||||
lab.setText(text)
|
||||
lab.setOrigin(x + 0.5*width, y_bottom+0.5*y_height)
|
||||
lab.boxAnchor = 'c'
|
||||
lab.width = width
|
||||
lab.height = y_height
|
||||
lab.fontSize = 6
|
||||
|
||||
r = Rect(x, y_bottom, width, y_height, fillColor=colors.cyan)
|
||||
g.add(r)
|
||||
g.add(lab)
|
||||
|
||||
#now for a label
|
||||
# would expect to color-code and add text
|
||||
return g
|
||||
|
||||
def draw(self):
|
||||
self.computeSize()
|
||||
g = Group()
|
||||
|
||||
# time column
|
||||
g.add(Rect(self.x, self.y, self._colWidths[0], self.height - self.trackRowHeight, fillColor=colors.cornsilk))
|
||||
|
||||
# track headers
|
||||
x = self.x + self._colWidths[0]
|
||||
y = self.y + self.height - self.trackRowHeight
|
||||
for trk in range(self._trackCount):
|
||||
wid = self._colWidths[trk+1]
|
||||
r = Rect(x, y, wid, self.trackRowHeight, fillColor=colors.yellow)
|
||||
s = String(x + 0.5*wid, y, 'Track %d' % trk, align='middle')
|
||||
g.add(r)
|
||||
g.add(s)
|
||||
x = x + wid
|
||||
|
||||
for talk in self._talksVisible:
|
||||
(title, speaker, trackId, day, start, duration) = talk
|
||||
r = self.getTalkRect(start, duration, trackId, title + '\n' + speaker)
|
||||
g.add(r)
|
||||
|
||||
|
||||
return g
|
||||
|
||||
|
||||
|
||||
|
||||
def test():
|
||||
"Make a conference event for day 1 of UP Python 2003"
|
||||
|
||||
|
||||
d = Drawing(400,200)
|
||||
|
||||
cal = EventCalendar()
|
||||
cal.x = 50
|
||||
cal.y = 25
|
||||
cal.data = [
|
||||
# these might be better as objects instead of tuples, since I
|
||||
# predict a large number of "optionsl" variables to affect
|
||||
# formatting in future.
|
||||
|
||||
#title, speaker, track id, day, start time (hrs), duration (hrs)
|
||||
# track ID is 1-based not zero-based!
|
||||
('Keynote: Why design another programming language?', 'Guido van Rossum', None, 1, 9.0, 1.0),
|
||||
|
||||
('Siena Web Service Architecture', 'Marc-Andre Lemburg', 1, 1, 10.5, 1.5),
|
||||
('Extreme Programming in Python', 'Chris Withers', 2, 1, 10.5, 1.5),
|
||||
('Pattern Experiences in C++', 'Mark Radford', 3, 1, 10.5, 1.5),
|
||||
('What is the Type of std::toupper()', 'Gabriel Dos Reis', 4, 1, 10.5, 1.5),
|
||||
('Linguistic Variables: Clear Thinking with Fuzzy Logic ', 'Walter Banks', 5, 1, 10.5, 1.5),
|
||||
|
||||
('lunch, short presentations, vendor presentations', '', None, 1, 12.0, 2.0),
|
||||
|
||||
("CORBA? Isn't that obsolete", 'Duncan Grisby', 1, 1, 14.0, 1.5),
|
||||
("Python Design Patterns", 'Duncan Booth', 2, 1, 14.0, 1.5),
|
||||
("Inside Security Checks and Safe Exceptions", 'Brandon Bray', 3, 1, 14.0, 1.5),
|
||||
("Studying at a Distance", 'Panel Discussion, Panel to include Alan Lenton & Francis Glassborow', 4, 1, 14.0, 1.5),
|
||||
("Coding Standards - Given the ANSI C Standard why do I still need a coding Standard", 'Randy Marques', 5, 1, 14.0, 1.5),
|
||||
|
||||
("RESTful Python", 'Hamish Lawson', 1, 1, 16.0, 1.5),
|
||||
("Parsing made easier - a radical old idea", 'Andrew Koenig', 2, 1, 16.0, 1.5),
|
||||
("C++ & Multimethods", 'Julian Smith', 3, 1, 16.0, 1.5),
|
||||
("C++ Threading", 'Kevlin Henney', 4, 1, 16.0, 1.5),
|
||||
("The Organisation Strikes Back", 'Alan Griffiths & Sarah Lees', 5, 1, 16.0, 1.5),
|
||||
|
||||
('Birds of a Feather meeting', '', None, 1, 17.5, 2.0),
|
||||
|
||||
('Keynote: In the Spirit of C', 'Greg Colvin', None, 2, 9.0, 1.0),
|
||||
|
||||
('The Infinite Filing Cabinet - object storage in Python', 'Jacob Hallen', 1, 2, 10.5, 1.5),
|
||||
('Introduction to Python and Jython for C++ and Java Programmers', 'Alex Martelli', 2, 2, 10.5, 1.5),
|
||||
('Template metaprogramming in Haskell', 'Simon Peyton Jones', 3, 2, 10.5, 1.5),
|
||||
('Plenty People Programming: C++ Programming in a Group, Workshop with a difference', 'Nico Josuttis', 4, 2, 10.5, 1.5),
|
||||
('Design and Implementation of the Boost Graph Library', 'Jeremy Siek', 5, 2, 10.5, 1.5),
|
||||
|
||||
('lunch, short presentations, vendor presentations', '', None, 2, 12.0, 2.0),
|
||||
|
||||
("Building GUI Applications with PythonCard and PyCrust", 'Andy Todd', 1, 2, 14.0, 1.5),
|
||||
("Integrating Python, C and C++", 'Duncan Booth', 2, 2, 14.0, 1.5),
|
||||
("Secrets and Pitfalls of Templates", 'Nicolai Josuttis & David Vandevoorde', 3, 2, 14.0, 1.5),
|
||||
("Being a Mentor", 'Panel Discussion, Panel to include Alan Lenton & Francis Glassborow', 4, 2, 14.0, 1.5),
|
||||
("The Embedded C Extensions to C", 'Willem Wakker', 5, 2, 14.0, 1.5),
|
||||
|
||||
("Lightning Talks", 'Paul Brian', 1, 2, 16.0, 1.5),
|
||||
("Scripting Java Applications with Jython", 'Anthony Eden', 2, 2, 16.0, 1.5),
|
||||
("Metaprogramming and the Boost Metaprogramming Library", 'David Abrahams', 3, 2, 16.0, 1.5),
|
||||
("A Common Vendor ABI for C++ -- GCC's why, what and not", 'Nathan Sidwell & Gabriel Dos Reis', 4, 2, 16.0, 1.5),
|
||||
("The Timing and Cost of Choices", 'Hubert Matthews', 5, 2, 16.0, 1.5),
|
||||
|
||||
('Birds of a Feather meeting', '', None, 2, 17.5, 2.0),
|
||||
|
||||
('Keynote: The Cost of C & C++ Compatibility', 'Andy Koenig', None, 3, 9.0, 1.0),
|
||||
|
||||
('Prying Eyes: Generic Observer Implementations in C++', 'Andrei Alexandrescu', 1, 2, 10.5, 1.5),
|
||||
('The Roadmap to Generative Programming With C++', 'Ulrich Eisenecker', 2, 2, 10.5, 1.5),
|
||||
('Design Patterns in C++ and C# for the Common Language Runtime', 'Brandon Bray', 3, 2, 10.5, 1.5),
|
||||
('Extreme Hour (XH): (workshop) - Jutta Eckstein and Nico Josuttis', 'Jutta Ecstein', 4, 2, 10.5, 1.5),
|
||||
('The Lambda Library : Unnamed Functions for C++', 'Jaako Jarvi', 5, 2, 10.5, 1.5),
|
||||
|
||||
('lunch, short presentations, vendor presentations', '', None, 3, 12.0, 2.0),
|
||||
|
||||
('Reflective Metaprogramming', 'Daveed Vandevoorde', 1, 3, 14.0, 1.5),
|
||||
('Advanced Template Issues and Solutions (double session)', 'Herb Sutter',2, 3, 14.0, 3),
|
||||
('Concurrent Programming in Java (double session)', 'Angelika Langer', 3, 3, 14.0, 3),
|
||||
('What can MISRA-C (2nd Edition) do for us?', 'Chris Hills', 4, 3, 14.0, 1.5),
|
||||
('C++ Metaprogramming Concepts and Results', 'Walter E Brown', 5, 3, 14.0, 1.5),
|
||||
|
||||
('Binding C++ to Python with the Boost Python Library', 'David Abrahams', 1, 3, 16.0, 1.5),
|
||||
('Using Aspect Oriented Programming for Enterprise Application Integration', 'Arno Schmidmeier', 4, 3, 16.0, 1.5),
|
||||
('Defective C++', 'Marc Paterno', 5, 3, 16.0, 1.5),
|
||||
|
||||
("Speakers' Banquet & Birds of a Feather meeting", '', None, 3, 17.5, 2.0),
|
||||
|
||||
('Keynote: The Internet, Software and Computers - A Report Card', 'Alan Lenton', None, 4, 9.0, 1.0),
|
||||
|
||||
('Multi-Platform Software Development; Lessons from the Boost libraries', 'Beman Dawes', 1, 5, 10.5, 1.5),
|
||||
('The Stability of the C++ ABI', 'Steve Clamage', 2, 5, 10.5, 1.5),
|
||||
('Generic Build Support - A Pragmatic Approach to the Software Build Process', 'Randy Marques', 3, 5, 10.5, 1.5),
|
||||
('How to Handle Project Managers: a survival guide', 'Barb Byro', 4, 5, 10.5, 1.5),
|
||||
|
||||
('lunch, ACCU AGM', '', None, 5, 12.0, 2.0),
|
||||
|
||||
('Sauce: An OO recursive descent parser; its design and implementation.', 'Jon Jagger', 1, 5, 14.0, 1.5),
|
||||
('GNIRTS ESAC REWOL - Bringing the UNIX filters to the C++ iostream library.', 'JC van Winkel', 2, 5, 14.0, 1.5),
|
||||
('Pattern Writing: Live and Direct', 'Frank Buschmann & Kevlin Henney', 3, 5, 14.0, 3.0),
|
||||
('The Future of Programming Languages - A Goldfish Bowl', 'Francis Glassborow and friends', 3, 5, 14.0, 1.5),
|
||||
|
||||
('Honey, I Shrunk the Threads: Compile-time checked multithreaded transactions in C++', 'Andrei Alexandrescu', 1, 5, 16.0, 1.5),
|
||||
('Fun and Functionality with Functors', 'Lois Goldthwaite', 2, 5, 16.0, 1.5),
|
||||
('Agile Enough?', 'Alan Griffiths', 4, 5, 16.0, 1.5),
|
||||
("Conference Closure: A brief plenary session", '', None, 5, 17.5, 0.5),
|
||||
|
||||
]
|
||||
|
||||
#return cal
|
||||
cal.day = 1
|
||||
|
||||
d.add(cal)
|
||||
|
||||
|
||||
for format in ['pdf']:#,'gif','png']:
|
||||
out = d.asString(format)
|
||||
open('eventcal.%s' % format, 'wb').write(out)
|
||||
print('saved eventcal.%s' % format)
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
||||
880
reportlab/graphics/widgets/flags.py
Normal file
880
reportlab/graphics/widgets/flags.py
Normal file
@@ -0,0 +1,880 @@
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/flags.py
|
||||
# Flag Widgets - a collection of flags as widgets
|
||||
# author: John Precedo (johnp@reportlab.com)
|
||||
|
||||
__version__=''' $Id$ '''
|
||||
__doc__="""This file is a collection of flag graphics as widgets.
|
||||
|
||||
All flags are represented at the ratio of 1:2, even where the official ratio for the flag is something else
|
||||
(such as 3:5 for the German national flag). The only exceptions are for where this would look _very_ wrong,
|
||||
such as the Danish flag whose (ratio is 28:37), or the Swiss flag (which is square).
|
||||
|
||||
Unless otherwise stated, these flags are all the 'national flags' of the countries, rather than their
|
||||
state flags, naval flags, ensigns or any other variants. (National flags are the flag flown by civilians
|
||||
of a country and the ones usually used to represent a country abroad. State flags are the variants used by
|
||||
the government and by diplomatic missions overseas).
|
||||
|
||||
To check on how close these are to the 'official' representations of flags, check the World Flag Database at
|
||||
http://www.flags.ndirect.co.uk/
|
||||
|
||||
The flags this file contains are:
|
||||
|
||||
EU Members:
|
||||
United Kingdom, Austria, Belgium, Denmark, Finland, France, Germany, Greece, Ireland, Italy, Luxembourg,
|
||||
Holland (The Netherlands), Spain, Sweden
|
||||
|
||||
Others:
|
||||
USA, Czech Republic, European Union, Switzerland, Turkey, Brazil
|
||||
|
||||
(Brazilian flag contributed by Publio da Costa Melo [publio@planetarium.com.br]).
|
||||
"""
|
||||
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.validators import *
|
||||
from reportlab.lib.attrmap import *
|
||||
from reportlab.graphics.shapes import Line, Rect, Polygon, Drawing, Group, String, Circle, Wedge
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
from reportlab.graphics import renderPDF
|
||||
from reportlab.graphics.widgets.signsandsymbols import _Symbol
|
||||
import copy
|
||||
from math import sin, cos, pi
|
||||
|
||||
validFlag=OneOf(None,
|
||||
'UK',
|
||||
'USA',
|
||||
'Afghanistan',
|
||||
'Austria',
|
||||
'Belgium',
|
||||
'China',
|
||||
'Cuba',
|
||||
'Denmark',
|
||||
'Finland',
|
||||
'France',
|
||||
'Germany',
|
||||
'Greece',
|
||||
'Ireland',
|
||||
'Italy',
|
||||
'Japan',
|
||||
'Luxembourg',
|
||||
'Holland',
|
||||
'Palestine',
|
||||
'Portugal',
|
||||
'Russia',
|
||||
'Spain',
|
||||
'Sweden',
|
||||
'Norway',
|
||||
'CzechRepublic',
|
||||
'Turkey',
|
||||
'Switzerland',
|
||||
'EU',
|
||||
'Brazil'
|
||||
)
|
||||
|
||||
_size = 100.
|
||||
|
||||
class Star(_Symbol):
|
||||
"""This draws a 5-pointed star.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'fillColor', 'strokeColor'
|
||||
|
||||
"""
|
||||
_attrMap = AttrMap(BASE=_Symbol,
|
||||
angle = AttrMapValue(isNumber, desc='angle in degrees'),
|
||||
)
|
||||
_size = 100.
|
||||
|
||||
def __init__(self):
|
||||
_Symbol.__init__(self)
|
||||
self.size = 100
|
||||
self.fillColor = colors.yellow
|
||||
self.strokeColor = None
|
||||
self.angle = 0
|
||||
|
||||
def demo(self):
|
||||
D = Drawing(200, 100)
|
||||
et = Star()
|
||||
et.x=50
|
||||
et.y=0
|
||||
D.add(et)
|
||||
labelFontSize = 10
|
||||
D.add(String(et.x+(et.size/2.0),(et.y-(1.2*labelFontSize)),
|
||||
et.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
return D
|
||||
|
||||
def draw(self):
|
||||
s = float(self.size) #abbreviate as we will use this a lot
|
||||
g = Group()
|
||||
|
||||
# new algorithm from markers.StarFive
|
||||
R = float(self.size)/2
|
||||
r = R*sin(18*(pi/180.0))/cos(36*(pi/180.0))
|
||||
P = []
|
||||
angle = 90
|
||||
for i in range(5):
|
||||
for radius in R, r:
|
||||
theta = angle*(pi/180.0)
|
||||
P.append(radius*cos(theta))
|
||||
P.append(radius*sin(theta))
|
||||
angle = angle + 36
|
||||
# star specific bits
|
||||
star = Polygon(P,
|
||||
fillColor = self.fillColor,
|
||||
strokeColor = self.strokeColor,
|
||||
strokeWidth=s/50)
|
||||
g.rotate(self.angle)
|
||||
g.shift(self.x+self.dx,self.y+self.dy)
|
||||
g.add(star)
|
||||
|
||||
return g
|
||||
|
||||
class Flag(_Symbol):
|
||||
"""This is a generic flag class that all the flags in this file use as a basis.
|
||||
|
||||
This class basically provides edges and a tidy-up routine to hide any bits of
|
||||
line that overlap the 'outside' of the flag
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'fillColor'
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(BASE=_Symbol,
|
||||
fillColor = AttrMapValue(isColor, desc='Background color'),
|
||||
border = AttrMapValue(isBoolean, 'Whether a background is drawn'),
|
||||
kind = AttrMapValue(validFlag, desc='Which flag'),
|
||||
)
|
||||
|
||||
_cache = {}
|
||||
|
||||
def __init__(self,**kw):
|
||||
_Symbol.__init__(self)
|
||||
self.kind = None
|
||||
self.size = 100
|
||||
self.fillColor = colors.white
|
||||
self.border=1
|
||||
self.setProperties(kw)
|
||||
|
||||
def availableFlagNames(self):
|
||||
'''return a list of the things we can display'''
|
||||
return [x for x in self._attrMap['kind'].validate._enum if x is not None]
|
||||
|
||||
def _Flag_None(self):
|
||||
s = _size # abbreviate as we will use this a lot
|
||||
g = Group()
|
||||
g.add(Rect(0, 0, s*2, s, fillColor = colors.purple, strokeColor = colors.black, strokeWidth=0))
|
||||
return g
|
||||
|
||||
def _borderDraw(self,f):
|
||||
s = self.size # abbreviate as we will use this a lot
|
||||
g = Group()
|
||||
g.add(f)
|
||||
x, y, sW = self.x+self.dx, self.y+self.dy, self.strokeWidth/2.
|
||||
g.insert(0,Rect(-sW, -sW, width=getattr(self,'_width',2*s)+3*sW, height=getattr(self,'_height',s)+2*sW,
|
||||
fillColor = None, strokeColor = self.strokeColor, strokeWidth=sW*2))
|
||||
g.shift(x,y)
|
||||
g.scale(s/_size, s/_size)
|
||||
return g
|
||||
|
||||
def draw(self):
|
||||
kind = self.kind or 'None'
|
||||
f = self._cache.get(kind)
|
||||
if not f:
|
||||
f = getattr(self,'_Flag_'+kind)()
|
||||
self._cache[kind] = f._explode()
|
||||
return self._borderDraw(f)
|
||||
|
||||
def clone(self):
|
||||
return copy.copy(self)
|
||||
|
||||
def demo(self):
|
||||
D = Drawing(200, 100)
|
||||
name = self.availableFlagNames()
|
||||
import time
|
||||
name = name[int(time.time()) % len(name)]
|
||||
fx = Flag()
|
||||
fx.kind = name
|
||||
fx.x = 0
|
||||
fx.y = 0
|
||||
D.add(fx)
|
||||
labelFontSize = 10
|
||||
D.add(String(fx.x+(fx.size/2.0),(fx.y-(1.2*labelFontSize)),
|
||||
name, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
labelFontSize = int(fx.size/4.0)
|
||||
D.add(String(fx.x+(fx.size),(fx.y+((fx.size/2.0))),
|
||||
"SAMPLE", fillColor=colors.gold, textAnchor='middle',
|
||||
fontSize=labelFontSize, fontName="Helvetica-Bold"))
|
||||
return D
|
||||
|
||||
def _Flag_UK(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
w = s*2
|
||||
g.add(Rect(0, 0, w, s, fillColor = colors.navy, strokeColor = colors.black, strokeWidth=0))
|
||||
g.add(Polygon([0,0, s*.225,0, w,s*(1-.1125), w,s, w-s*.225,s, 0, s*.1125], fillColor = colors.mintcream, strokeColor=None, strokeWidth=0))
|
||||
g.add(Polygon([0,s*(1-.1125), 0, s, s*.225,s, w, s*.1125, w,0, w-s*.225,0], fillColor = colors.mintcream, strokeColor=None, strokeWidth=0))
|
||||
g.add(Polygon([0, s-(s/15.0), (s-((s/10.0)*4)), (s*0.65), (s-(s/10.0)*3), (s*0.65), 0, s], fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
||||
g.add(Polygon([0, 0, (s-((s/10.0)*3)), (s*0.35), (s-((s/10.0)*2)), (s*0.35), (s/10.0), 0], fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
||||
g.add(Polygon([w, s, (s+((s/10.0)*3)), (s*0.65), (s+((s/10.0)*2)), (s*0.65), w-(s/10.0), s], fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
||||
g.add(Polygon([w, (s/15.0), (s+((s/10.0)*4)), (s*0.35), (s+((s/10.0)*3)), (s*0.35), w, 0], fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
||||
g.add(Rect(((s*0.42)*2), 0, width=(0.16*s)*2, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0))
|
||||
g.add(Rect(0, (s*0.35), width=w, height=s*0.3, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0))
|
||||
g.add(Rect(((s*0.45)*2), 0, width=(0.1*s)*2, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
||||
g.add(Rect(0, (s*0.4), width=w, height=s*0.2, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
||||
return g
|
||||
|
||||
def _Flag_USA(self):
|
||||
s = _size # abbreviate as we will use this a lot
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
for stripecounter in range (13,0, -1):
|
||||
stripeheight = s/13.0
|
||||
if not (stripecounter%2 == 0):
|
||||
stripecolor = colors.red
|
||||
else:
|
||||
stripecolor = colors.mintcream
|
||||
redorwhiteline = Rect(0, (s-(stripeheight*stripecounter)), width=s*2, height=stripeheight,
|
||||
fillColor = stripecolor, strokeColor = None, strokeWidth=20)
|
||||
g.add(redorwhiteline)
|
||||
|
||||
bluebox = Rect(0, (s-(stripeheight*7)), width=0.8*s, height=stripeheight*7,
|
||||
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
||||
g.add(bluebox)
|
||||
|
||||
lss = s*0.045
|
||||
lss2 = lss/2.0
|
||||
s9 = s/9.0
|
||||
s7 = s/7.0
|
||||
for starxcounter in range(5):
|
||||
for starycounter in range(4):
|
||||
ls = Star()
|
||||
ls.size = lss
|
||||
ls.x = 0-s/22.0+lss/2.0+s7+starxcounter*s7
|
||||
ls.fillColor = colors.mintcream
|
||||
ls.y = s-(starycounter+1)*s9+lss2
|
||||
g.add(ls)
|
||||
|
||||
for starxcounter in range(6):
|
||||
for starycounter in range(5):
|
||||
ls = Star()
|
||||
ls.size = lss
|
||||
ls.x = 0-(s/22.0)+lss/2.0+s/14.0+starxcounter*s7
|
||||
ls.fillColor = colors.mintcream
|
||||
ls.y = s-(starycounter+1)*s9+(s/18.0)+lss2
|
||||
g.add(ls)
|
||||
return g
|
||||
|
||||
def _Flag_Afghanistan(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
greenbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.limegreen, strokeColor = None, strokeWidth=0)
|
||||
g.add(greenbox)
|
||||
|
||||
blackbox = Rect(0, 0, width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.black, strokeColor = None, strokeWidth=0)
|
||||
g.add(blackbox)
|
||||
return g
|
||||
|
||||
def _Flag_Austria(self):
|
||||
s = _size # abbreviate as we will use this a lot
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s, fillColor = colors.mintcream,
|
||||
strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
|
||||
redbox1 = Rect(0, 0, width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
||||
g.add(redbox1)
|
||||
|
||||
redbox2 = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
||||
g.add(redbox2)
|
||||
return g
|
||||
|
||||
def _Flag_Belgium(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = colors.black, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
|
||||
box1 = Rect(0, 0, width=(s/3.0)*2.0, height=s,
|
||||
fillColor = colors.black, strokeColor = None, strokeWidth=0)
|
||||
g.add(box1)
|
||||
|
||||
box2 = Rect(((s/3.0)*2.0), 0, width=(s/3.0)*2.0, height=s,
|
||||
fillColor = colors.gold, strokeColor = None, strokeWidth=0)
|
||||
g.add(box2)
|
||||
|
||||
box3 = Rect(((s/3.0)*4.0), 0, width=(s/3.0)*2.0, height=s,
|
||||
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
||||
g.add(box3)
|
||||
return g
|
||||
|
||||
def _Flag_China(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
self._width = w = s*1.5
|
||||
g.add(Rect(0, 0, w, s, fillColor=colors.red, strokeColor=None, strokeWidth=0))
|
||||
|
||||
def addStar(x,y,size,angle,g=g,w=s/20.0,x0=0,y0=s/2.0):
|
||||
s = Star()
|
||||
s.fillColor=colors.yellow
|
||||
s.angle = angle
|
||||
s.size = size*w*2
|
||||
s.x = x*w+x0
|
||||
s.y = y*w+y0
|
||||
g.add(s)
|
||||
|
||||
addStar(5,5,3, 0)
|
||||
addStar(10,1,1,36.86989765)
|
||||
addStar(12,3,1,8.213210702)
|
||||
addStar(12,6,1,16.60154960)
|
||||
addStar(10,8,1,53.13010235)
|
||||
return g
|
||||
|
||||
def _Flag_Cuba(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
for i in range(5):
|
||||
stripe = Rect(0, i*s/5.0, width=s*2, height=s/5.0,
|
||||
fillColor = [colors.darkblue, colors.mintcream][i%2],
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(stripe)
|
||||
|
||||
redwedge = Polygon(points = [ 0, 0, 4*s/5.0, (s/2.0), 0, s],
|
||||
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
||||
g.add(redwedge)
|
||||
|
||||
star = Star()
|
||||
star.x = 2.5*s/10.0
|
||||
star.y = s/2.0
|
||||
star.size = 3*s/10.0
|
||||
star.fillColor = colors.white
|
||||
g.add(star)
|
||||
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = None,
|
||||
strokeColor = colors.black,
|
||||
strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
return g
|
||||
|
||||
def _Flag_Denmark(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
self._width = w = s*1.4
|
||||
|
||||
box = Rect(0, 0, w, s,
|
||||
fillColor = colors.red, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
whitebox1 = Rect(((s/5.0)*2), 0, width=s/6.0, height=s,
|
||||
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
||||
g.add(whitebox1)
|
||||
|
||||
whitebox2 = Rect(0, ((s/2.0)-(s/12.0)), width=w, height=s/6.0,
|
||||
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
||||
g.add(whitebox2)
|
||||
return g
|
||||
|
||||
def _Flag_Finland(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
# crossbox specific bits
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = colors.ghostwhite, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
blueline1 = Rect((s*0.6), 0, width=0.3*s, height=s,
|
||||
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
||||
g.add(blueline1)
|
||||
|
||||
blueline2 = Rect(0, (s*0.4), width=s*2, height=s*0.3,
|
||||
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
||||
g.add(blueline2)
|
||||
return g
|
||||
|
||||
def _Flag_France(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s, fillColor = colors.navy, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
bluebox = Rect(0, 0, width=((s/3.0)*2.0), height=s,
|
||||
fillColor = colors.blue, strokeColor = None, strokeWidth=0)
|
||||
g.add(bluebox)
|
||||
|
||||
whitebox = Rect(((s/3.0)*2.0), 0, width=((s/3.0)*2.0), height=s,
|
||||
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
||||
g.add(whitebox)
|
||||
|
||||
redbox = Rect(((s/3.0)*4.0), 0, width=((s/3.0)*2.0), height=s,
|
||||
fillColor = colors.red,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(redbox)
|
||||
return g
|
||||
|
||||
def _Flag_Germany(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = colors.gold, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
blackbox1 = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.black, strokeColor = None, strokeWidth=0)
|
||||
g.add(blackbox1)
|
||||
|
||||
redbox1 = Rect(0, (s/3.0), width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.orangered, strokeColor = None, strokeWidth=0)
|
||||
g.add(redbox1)
|
||||
return g
|
||||
|
||||
def _Flag_Greece(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s, fillColor = colors.gold,
|
||||
strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
for stripecounter in range (9,0, -1):
|
||||
stripeheight = s/9.0
|
||||
if not (stripecounter%2 == 0):
|
||||
stripecolor = colors.deepskyblue
|
||||
else:
|
||||
stripecolor = colors.mintcream
|
||||
|
||||
blueorwhiteline = Rect(0, (s-(stripeheight*stripecounter)), width=s*2, height=stripeheight,
|
||||
fillColor = stripecolor, strokeColor = None, strokeWidth=20)
|
||||
g.add(blueorwhiteline)
|
||||
|
||||
bluebox1 = Rect(0, ((s)-stripeheight*5), width=(stripeheight*5), height=stripeheight*5,
|
||||
fillColor = colors.deepskyblue, strokeColor = None, strokeWidth=0)
|
||||
g.add(bluebox1)
|
||||
|
||||
whiteline1 = Rect(0, ((s)-stripeheight*3), width=stripeheight*5, height=stripeheight,
|
||||
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
||||
g.add(whiteline1)
|
||||
|
||||
whiteline2 = Rect((stripeheight*2), ((s)-stripeheight*5), width=stripeheight, height=stripeheight*5,
|
||||
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
||||
g.add(whiteline2)
|
||||
|
||||
return g
|
||||
|
||||
def _Flag_Ireland(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = colors.forestgreen, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
whitebox = Rect(((s*2.0)/3.0), 0, width=(2.0*(s*2.0)/3.0), height=s,
|
||||
fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)
|
||||
g.add(whitebox)
|
||||
|
||||
orangebox = Rect(((2.0*(s*2.0)/3.0)), 0, width=(s*2.0)/3.0, height=s,
|
||||
fillColor = colors.darkorange, strokeColor = None, strokeWidth=0)
|
||||
g.add(orangebox)
|
||||
return g
|
||||
|
||||
def _Flag_Italy(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
g.add(Rect(0,0,s*2,s,fillColor=colors.forestgreen,strokeColor=None, strokeWidth=0))
|
||||
g.add(Rect((2*s)/3.0, 0, width=(s*4)/3.0, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0))
|
||||
g.add(Rect((4*s)/3.0, 0, width=(s*2)/3.0, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
||||
return g
|
||||
|
||||
def _Flag_Japan(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
w = self._width = s*1.5
|
||||
g.add(Rect(0,0,w,s,fillColor=colors.mintcream,strokeColor=None, strokeWidth=0))
|
||||
g.add(Circle(cx=w/2.0,cy=s/2.0,r=0.3*w,fillColor=colors.red,strokeColor=None, strokeWidth=0))
|
||||
return g
|
||||
|
||||
def _Flag_Luxembourg(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
redbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
||||
g.add(redbox)
|
||||
|
||||
bluebox = Rect(0, 0, width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.dodgerblue, strokeColor = None, strokeWidth=0)
|
||||
g.add(bluebox)
|
||||
return g
|
||||
|
||||
def _Flag_Holland(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
redbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
||||
g.add(redbox)
|
||||
|
||||
bluebox = Rect(0, 0, width=s*2.0, height=s/3.0,
|
||||
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
||||
g.add(bluebox)
|
||||
return g
|
||||
|
||||
def _Flag_Portugal(self):
|
||||
return Group()
|
||||
|
||||
def _Flag_Russia(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
w = self._width = s*1.5
|
||||
t = s/3.0
|
||||
g.add(Rect(0, 0, width=w, height=t, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
||||
g.add(Rect(0, t, width=w, height=t, fillColor = colors.blue, strokeColor = None, strokeWidth=0))
|
||||
g.add(Rect(0, 2*t, width=w, height=t, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0))
|
||||
return g
|
||||
|
||||
def _Flag_Spain(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
w = self._width = s*1.5
|
||||
g.add(Rect(0, 0, width=w, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0))
|
||||
g.add(Rect(0, (s/4.0), width=w, height=s/2.0, fillColor = colors.yellow, strokeColor = None, strokeWidth=0))
|
||||
return g
|
||||
|
||||
def _Flag_Sweden(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
self._width = s*1.4
|
||||
box = Rect(0, 0, self._width, s,
|
||||
fillColor = colors.dodgerblue, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
box1 = Rect(((s/5.0)*2), 0, width=s/6.0, height=s,
|
||||
fillColor = colors.gold, strokeColor = None, strokeWidth=0)
|
||||
g.add(box1)
|
||||
|
||||
box2 = Rect(0, ((s/2.0)-(s/12.0)), width=self._width, height=s/6.0,
|
||||
fillColor = colors.gold,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(box2)
|
||||
return g
|
||||
|
||||
def _Flag_Norway(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
self._width = s*1.4
|
||||
|
||||
box = Rect(0, 0, self._width, s,
|
||||
fillColor = colors.red, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
box = Rect(0, 0, self._width, s,
|
||||
fillColor = colors.red, strokeColor = colors.black, strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
whiteline1 = Rect(((s*0.2)*2), 0, width=s*0.2, height=s,
|
||||
fillColor = colors.ghostwhite, strokeColor = None, strokeWidth=0)
|
||||
g.add(whiteline1)
|
||||
|
||||
whiteline2 = Rect(0, (s*0.4), width=self._width, height=s*0.2,
|
||||
fillColor = colors.ghostwhite, strokeColor = None, strokeWidth=0)
|
||||
g.add(whiteline2)
|
||||
|
||||
blueline1 = Rect(((s*0.225)*2), 0, width=0.1*s, height=s,
|
||||
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
||||
g.add(blueline1)
|
||||
|
||||
blueline2 = Rect(0, (s*0.45), width=self._width, height=s*0.1,
|
||||
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
||||
g.add(blueline2)
|
||||
return g
|
||||
|
||||
def _Flag_CzechRepublic(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = colors.mintcream,
|
||||
strokeColor = colors.black,
|
||||
strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
redbox = Rect(0, 0, width=s*2, height=s/2.0,
|
||||
fillColor = colors.red,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(redbox)
|
||||
|
||||
bluewedge = Polygon(points = [ 0, 0, s, (s/2.0), 0, s],
|
||||
fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)
|
||||
g.add(bluewedge)
|
||||
return g
|
||||
|
||||
def _Flag_Palestine(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
box = Rect(0, s/3.0, s*2, s/3.0,
|
||||
fillColor = colors.mintcream,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
greenbox = Rect(0, 0, width=s*2, height=s/3.0,
|
||||
fillColor = colors.limegreen,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(greenbox)
|
||||
|
||||
blackbox = Rect(0, 2*s/3.0, width=s*2, height=s/3.0,
|
||||
fillColor = colors.black,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(blackbox)
|
||||
|
||||
redwedge = Polygon(points = [ 0, 0, 2*s/3.0, (s/2.0), 0, s],
|
||||
fillColor = colors.red, strokeColor = None, strokeWidth=0)
|
||||
g.add(redwedge)
|
||||
return g
|
||||
|
||||
def _Flag_Turkey(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
|
||||
box = Rect(0, 0, s*2, s,
|
||||
fillColor = colors.red,
|
||||
strokeColor = colors.black,
|
||||
strokeWidth=0)
|
||||
g.add(box)
|
||||
|
||||
whitecircle = Circle(cx=((s*0.35)*2), cy=s/2.0, r=s*0.3,
|
||||
fillColor = colors.mintcream,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(whitecircle)
|
||||
|
||||
redcircle = Circle(cx=((s*0.39)*2), cy=s/2.0, r=s*0.24,
|
||||
fillColor = colors.red,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(redcircle)
|
||||
|
||||
ws = Star()
|
||||
ws.angle = 15
|
||||
ws.size = s/5.0
|
||||
ws.x = (s*0.5)*2+ws.size/2.0
|
||||
ws.y = (s*0.5)
|
||||
ws.fillColor = colors.mintcream
|
||||
ws.strokeColor = None
|
||||
g.add(ws)
|
||||
return g
|
||||
|
||||
def _Flag_Switzerland(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
self._width = s
|
||||
|
||||
g.add(Rect(0, 0, s, s, fillColor = colors.red, strokeColor = colors.black, strokeWidth=0))
|
||||
g.add(Line((s/2.0), (s/5.5), (s/2), (s-(s/5.5)),
|
||||
fillColor = colors.mintcream, strokeColor = colors.mintcream, strokeWidth=(s/5.0)))
|
||||
g.add(Line((s/5.5), (s/2.0), (s-(s/5.5)), (s/2.0),
|
||||
fillColor = colors.mintcream, strokeColor = colors.mintcream, strokeWidth=s/5.0))
|
||||
return g
|
||||
|
||||
def _Flag_EU(self):
|
||||
s = _size
|
||||
g = Group()
|
||||
w = self._width = 1.5*s
|
||||
|
||||
g.add(Rect(0, 0, w, s, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0))
|
||||
centerx=w/2.0
|
||||
centery=s/2.0
|
||||
radius=s/3.0
|
||||
yradius = radius
|
||||
xradius = radius
|
||||
nStars = 12
|
||||
delta = 2*pi/nStars
|
||||
for i in range(nStars):
|
||||
rad = i*delta
|
||||
gs = Star()
|
||||
gs.x=cos(rad)*radius+centerx
|
||||
gs.y=sin(rad)*radius+centery
|
||||
gs.size=s/10.0
|
||||
gs.fillColor=colors.gold
|
||||
g.add(gs)
|
||||
return g
|
||||
|
||||
def _Flag_Brazil(self):
|
||||
s = _size # abbreviate as we will use this a lot
|
||||
g = Group()
|
||||
|
||||
m = s/14.0
|
||||
self._width = w = (m * 20)
|
||||
|
||||
def addStar(x,y,size, g=g, w=w, s=s, m=m):
|
||||
st = Star()
|
||||
st.fillColor=colors.mintcream
|
||||
st.size = size*m
|
||||
st.x = (w/2.0) + (x * (0.35 * m))
|
||||
st.y = (s/2.0) + (y * (0.35 * m))
|
||||
g.add(st)
|
||||
|
||||
g.add(Rect(0, 0, w, s, fillColor = colors.green, strokeColor = None, strokeWidth=0))
|
||||
g.add(Polygon(points = [ 1.7*m, (s/2.0), (w/2.0), s-(1.7*m), w-(1.7*m),(s/2.0),(w/2.0), 1.7*m],
|
||||
fillColor = colors.yellow, strokeColor = None, strokeWidth=0))
|
||||
g.add(Circle(cx=w/2.0, cy=s/2.0, r=3.5*m,
|
||||
fillColor=colors.blue,strokeColor=None, strokeWidth=0))
|
||||
g.add(Wedge((w/2.0)-(2*m), 0, 8.5*m, 50, 98.1, 8.5*m,
|
||||
fillColor=colors.mintcream,strokeColor=None, strokeWidth=0))
|
||||
g.add(Wedge((w/2.0), (s/2.0), 3.501*m, 156, 352, 3.501*m,
|
||||
fillColor=colors.mintcream,strokeColor=None, strokeWidth=0))
|
||||
g.add(Wedge((w/2.0)-(2*m), 0, 8*m, 48.1, 100, 8*m,
|
||||
fillColor=colors.blue,strokeColor=None, strokeWidth=0))
|
||||
g.add(Rect(0, 0, w, (s/4.0) + 1.7*m,
|
||||
fillColor = colors.green, strokeColor = None, strokeWidth=0))
|
||||
g.add(Polygon(points = [ 1.7*m,(s/2.0), (w/2.0),s/2.0 - 2*m, w-(1.7*m),(s/2.0) , (w/2.0),1.7*m],
|
||||
fillColor = colors.yellow, strokeColor = None, strokeWidth=0))
|
||||
g.add(Wedge(w/2.0, s/2.0, 3.502*m, 166, 342.1, 3.502*m,
|
||||
fillColor=colors.blue,strokeColor=None, strokeWidth=0))
|
||||
|
||||
addStar(3.2,3.5,0.3)
|
||||
addStar(-8.5,1.5,0.3)
|
||||
addStar(-7.5,-3,0.3)
|
||||
addStar(-4,-5.5,0.3)
|
||||
addStar(0,-4.5,0.3)
|
||||
addStar(7,-3.5,0.3)
|
||||
addStar(-3.5,-0.5,0.25)
|
||||
addStar(0,-1.5,0.25)
|
||||
addStar(1,-2.5,0.25)
|
||||
addStar(3,-7,0.25)
|
||||
addStar(5,-6.5,0.25)
|
||||
addStar(6.5,-5,0.25)
|
||||
addStar(7,-4.5,0.25)
|
||||
addStar(-5.5,-3.2,0.25)
|
||||
addStar(-6,-4.2,0.25)
|
||||
addStar(-1,-2.75,0.2)
|
||||
addStar(2,-5.5,0.2)
|
||||
addStar(4,-5.5,0.2)
|
||||
addStar(5,-7.5,0.2)
|
||||
addStar(5,-5.5,0.2)
|
||||
addStar(6,-5.5,0.2)
|
||||
addStar(-8.8,-3.2,0.2)
|
||||
addStar(2.5,0.5,0.2)
|
||||
addStar(-0.2,-3.2,0.14)
|
||||
addStar(-7.2,-2,0.14)
|
||||
addStar(0,-8,0.1)
|
||||
|
||||
sTmp = "ORDEM E PROGRESSO"
|
||||
nTmp = len(sTmp)
|
||||
delta = 0.850848010347/nTmp
|
||||
radius = 7.9 *m
|
||||
centerx = (w/2.0)-(2*m)
|
||||
centery = 0
|
||||
for i in range(nTmp):
|
||||
rad = 2*pi - i*delta -4.60766922527
|
||||
x=cos(rad)*radius+centerx
|
||||
y=sin(rad)*radius+centery
|
||||
if i == 6:
|
||||
z = 0.35*m
|
||||
else:
|
||||
z= 0.45*m
|
||||
g2 = Group(String(x, y, sTmp[i], fontName='Helvetica-Bold',
|
||||
fontSize = z,strokeColor=None,fillColor=colors.green))
|
||||
g2.rotate(rad)
|
||||
g.add(g2)
|
||||
return g
|
||||
|
||||
def makeFlag(name):
|
||||
flag = Flag()
|
||||
flag.kind = name
|
||||
return flag
|
||||
|
||||
def test():
|
||||
"""This function produces three pdf files with examples of all the signs and symbols from this file.
|
||||
"""
|
||||
# page 1
|
||||
|
||||
labelFontSize = 10
|
||||
|
||||
X = (20,245)
|
||||
|
||||
flags = [
|
||||
'UK',
|
||||
'USA',
|
||||
'Afghanistan',
|
||||
'Austria',
|
||||
'Belgium',
|
||||
'Denmark',
|
||||
'Cuba',
|
||||
'Finland',
|
||||
'France',
|
||||
'Germany',
|
||||
'Greece',
|
||||
'Ireland',
|
||||
'Italy',
|
||||
'Luxembourg',
|
||||
'Holland',
|
||||
'Palestine',
|
||||
'Portugal',
|
||||
'Spain',
|
||||
'Sweden',
|
||||
'Norway',
|
||||
'CzechRepublic',
|
||||
'Turkey',
|
||||
'Switzerland',
|
||||
'EU',
|
||||
'Brazil',
|
||||
]
|
||||
y = Y0 = 530
|
||||
f = 0
|
||||
D = None
|
||||
for name in flags:
|
||||
if not D: D = Drawing(450,650)
|
||||
flag = makeFlag(name)
|
||||
i = flags.index(name)
|
||||
flag.x = X[i%2]
|
||||
flag.y = y
|
||||
D.add(flag)
|
||||
D.add(String(flag.x+(flag.size/2.0),(flag.y-(1.2*labelFontSize)),
|
||||
name, fillColor=colors.black, textAnchor='middle', fontSize=labelFontSize))
|
||||
if i%2: y = y - 125
|
||||
if (i%2 and y<0) or name==flags[-1]:
|
||||
renderPDF.drawToFile(D, 'flags%02d.pdf'%f, 'flags.py - Page #%d'%(f+1))
|
||||
y = Y0
|
||||
f = f+1
|
||||
D = None
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
||||
519
reportlab/graphics/widgets/grids.py
Normal file
519
reportlab/graphics/widgets/grids.py
Normal file
@@ -0,0 +1,519 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2012
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/grids.py
|
||||
__version__=''' $Id$ '''
|
||||
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.validators import isNumber, isColorOrNone, isBoolean, isListOfNumbers, OneOf, isListOfColors, isNumberOrNone
|
||||
from reportlab.lib.attrmap import AttrMap, AttrMapValue
|
||||
from reportlab.graphics.shapes import Drawing, Group, Line, Rect, LineShape, definePath, EmptyClipPath
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
|
||||
def frange(start, end=None, inc=None):
|
||||
"A range function, that does accept float increments..."
|
||||
|
||||
if end == None:
|
||||
end = start + 0.0
|
||||
start = 0.0
|
||||
|
||||
if inc == None:
|
||||
inc = 1.0
|
||||
|
||||
L = []
|
||||
end = end - inc*0.0001 #to avoid numrical problems
|
||||
while 1:
|
||||
next = start + len(L) * inc
|
||||
if inc > 0 and next >= end:
|
||||
break
|
||||
elif inc < 0 and next <= end:
|
||||
break
|
||||
L.append(next)
|
||||
|
||||
return L
|
||||
|
||||
|
||||
def makeDistancesList(list):
|
||||
"""Returns a list of distances between adjacent numbers in some input list.
|
||||
|
||||
E.g. [1, 1, 2, 3, 5, 7] -> [0, 1, 1, 2, 2]
|
||||
"""
|
||||
|
||||
d = []
|
||||
for i in range(len(list[:-1])):
|
||||
d.append(list[i+1] - list[i])
|
||||
|
||||
return d
|
||||
|
||||
|
||||
class Grid(Widget):
|
||||
"""This makes a rectangular grid of equidistant stripes.
|
||||
|
||||
The grid contains an outer border rectangle, and stripes
|
||||
inside which can be drawn with lines and/or as solid tiles.
|
||||
The drawing order is: outer rectangle, then lines and tiles.
|
||||
|
||||
The stripes' width is indicated as 'delta'. The sequence of
|
||||
stripes can have an offset named 'delta0'. Both values need
|
||||
to be positive!
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(
|
||||
x = AttrMapValue(isNumber, desc="The grid's lower-left x position."),
|
||||
y = AttrMapValue(isNumber, desc="The grid's lower-left y position."),
|
||||
width = AttrMapValue(isNumber, desc="The grid's width."),
|
||||
height = AttrMapValue(isNumber, desc="The grid's height."),
|
||||
orientation = AttrMapValue(OneOf(('vertical', 'horizontal')),
|
||||
desc='Determines if stripes are vertical or horizontal.'),
|
||||
useLines = AttrMapValue(OneOf((0, 1)),
|
||||
desc='Determines if stripes are drawn with lines.'),
|
||||
useRects = AttrMapValue(OneOf((0, 1)),
|
||||
desc='Determines if stripes are drawn with solid rectangles.'),
|
||||
delta = AttrMapValue(isNumber,
|
||||
desc='Determines the width/height of the stripes.'),
|
||||
delta0 = AttrMapValue(isNumber,
|
||||
desc='Determines the stripes initial width/height offset.'),
|
||||
deltaSteps = AttrMapValue(isListOfNumbers,
|
||||
desc='List of deltas to be used cyclically.'),
|
||||
stripeColors = AttrMapValue(isListOfColors,
|
||||
desc='Colors applied cyclically in the right or upper direction.'),
|
||||
fillColor = AttrMapValue(isColorOrNone,
|
||||
desc='Background color for entire rectangle.'),
|
||||
strokeColor = AttrMapValue(isColorOrNone,
|
||||
desc='Color used for lines.'),
|
||||
strokeWidth = AttrMapValue(isNumber,
|
||||
desc='Width used for lines.'),
|
||||
rectStrokeColor = AttrMapValue(isColorOrNone, desc='Color for outer rect stroke.'),
|
||||
rectStrokeWidth = AttrMapValue(isNumberOrNone, desc='Width for outer rect stroke.'),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.width = 100
|
||||
self.height = 100
|
||||
self.orientation = 'vertical'
|
||||
self.useLines = 0
|
||||
self.useRects = 1
|
||||
self.delta = 20
|
||||
self.delta0 = 0
|
||||
self.deltaSteps = []
|
||||
self.fillColor = colors.white
|
||||
self.stripeColors = [colors.red, colors.green, colors.blue]
|
||||
self.strokeColor = colors.black
|
||||
self.strokeWidth = 2
|
||||
|
||||
|
||||
def demo(self):
|
||||
D = Drawing(100, 100)
|
||||
|
||||
g = Grid()
|
||||
D.add(g)
|
||||
|
||||
return D
|
||||
|
||||
def makeOuterRect(self):
|
||||
strokeColor = getattr(self,'rectStrokeColor',self.strokeColor)
|
||||
strokeWidth = getattr(self,'rectStrokeWidth',self.strokeWidth)
|
||||
if self.fillColor or (strokeColor and strokeWidth):
|
||||
rect = Rect(self.x, self.y, self.width, self.height)
|
||||
rect.fillColor = self.fillColor
|
||||
rect.strokeColor = strokeColor
|
||||
rect.strokeWidth = strokeWidth
|
||||
return rect
|
||||
else:
|
||||
return None
|
||||
|
||||
def makeLinePosList(self, start, isX=0):
|
||||
"Returns a list of positions where to place lines."
|
||||
|
||||
w, h = self.width, self.height
|
||||
if isX:
|
||||
length = w
|
||||
else:
|
||||
length = h
|
||||
if self.deltaSteps:
|
||||
r = [start + self.delta0]
|
||||
i = 0
|
||||
while 1:
|
||||
if r[-1] > start + length:
|
||||
del r[-1]
|
||||
break
|
||||
r.append(r[-1] + self.deltaSteps[i % len(self.deltaSteps)])
|
||||
i = i + 1
|
||||
else:
|
||||
r = frange(start + self.delta0, start + length, self.delta)
|
||||
|
||||
r.append(start + length)
|
||||
if self.delta0 != 0:
|
||||
r.insert(0, start)
|
||||
#print 'Grid.makeLinePosList() -> %s' % r
|
||||
return r
|
||||
|
||||
|
||||
def makeInnerLines(self):
|
||||
# inner grid lines
|
||||
group = Group()
|
||||
|
||||
w, h = self.width, self.height
|
||||
|
||||
if self.useLines == 1:
|
||||
if self.orientation == 'vertical':
|
||||
r = self.makeLinePosList(self.x, isX=1)
|
||||
for x in r:
|
||||
line = Line(x, self.y, x, self.y + h)
|
||||
line.strokeColor = self.strokeColor
|
||||
line.strokeWidth = self.strokeWidth
|
||||
group.add(line)
|
||||
elif self.orientation == 'horizontal':
|
||||
r = self.makeLinePosList(self.y, isX=0)
|
||||
for y in r:
|
||||
line = Line(self.x, y, self.x + w, y)
|
||||
line.strokeColor = self.strokeColor
|
||||
line.strokeWidth = self.strokeWidth
|
||||
group.add(line)
|
||||
|
||||
return group
|
||||
|
||||
|
||||
def makeInnerTiles(self):
|
||||
# inner grid lines
|
||||
group = Group()
|
||||
|
||||
w, h = self.width, self.height
|
||||
|
||||
# inner grid stripes (solid rectangles)
|
||||
if self.useRects == 1:
|
||||
cols = self.stripeColors
|
||||
|
||||
if self.orientation == 'vertical':
|
||||
r = self.makeLinePosList(self.x, isX=1)
|
||||
elif self.orientation == 'horizontal':
|
||||
r = self.makeLinePosList(self.y, isX=0)
|
||||
|
||||
dist = makeDistancesList(r)
|
||||
|
||||
i = 0
|
||||
for j in range(len(dist)):
|
||||
if self.orientation == 'vertical':
|
||||
x = r[j]
|
||||
stripe = Rect(x, self.y, dist[j], h)
|
||||
elif self.orientation == 'horizontal':
|
||||
y = r[j]
|
||||
stripe = Rect(self.x, y, w, dist[j])
|
||||
stripe.fillColor = cols[i % len(cols)]
|
||||
stripe.strokeColor = None
|
||||
group.add(stripe)
|
||||
i = i + 1
|
||||
|
||||
return group
|
||||
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
group = Group()
|
||||
|
||||
group.add(self.makeOuterRect())
|
||||
group.add(self.makeInnerTiles())
|
||||
group.add(self.makeInnerLines(),name='_gridLines')
|
||||
|
||||
return group
|
||||
|
||||
|
||||
class DoubleGrid(Widget):
|
||||
"""This combines two ordinary Grid objects orthogonal to each other.
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(
|
||||
x = AttrMapValue(isNumber, desc="The grid's lower-left x position."),
|
||||
y = AttrMapValue(isNumber, desc="The grid's lower-left y position."),
|
||||
width = AttrMapValue(isNumber, desc="The grid's width."),
|
||||
height = AttrMapValue(isNumber, desc="The grid's height."),
|
||||
grid0 = AttrMapValue(None, desc="The first grid component."),
|
||||
grid1 = AttrMapValue(None, desc="The second grid component."),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.width = 100
|
||||
self.height = 100
|
||||
|
||||
g0 = Grid()
|
||||
g0.x = self.x
|
||||
g0.y = self.y
|
||||
g0.width = self.width
|
||||
g0.height = self.height
|
||||
g0.orientation = 'vertical'
|
||||
g0.useLines = 1
|
||||
g0.useRects = 0
|
||||
g0.delta = 20
|
||||
g0.delta0 = 0
|
||||
g0.deltaSteps = []
|
||||
g0.fillColor = colors.white
|
||||
g0.stripeColors = [colors.red, colors.green, colors.blue]
|
||||
g0.strokeColor = colors.black
|
||||
g0.strokeWidth = 1
|
||||
|
||||
g1 = Grid()
|
||||
g1.x = self.x
|
||||
g1.y = self.y
|
||||
g1.width = self.width
|
||||
g1.height = self.height
|
||||
g1.orientation = 'horizontal'
|
||||
g1.useLines = 1
|
||||
g1.useRects = 0
|
||||
g1.delta = 20
|
||||
g1.delta0 = 0
|
||||
g1.deltaSteps = []
|
||||
g1.fillColor = colors.white
|
||||
g1.stripeColors = [colors.red, colors.green, colors.blue]
|
||||
g1.strokeColor = colors.black
|
||||
g1.strokeWidth = 1
|
||||
|
||||
self.grid0 = g0
|
||||
self.grid1 = g1
|
||||
|
||||
|
||||
## # This gives an AttributeError:
|
||||
## # DoubleGrid instance has no attribute 'grid0'
|
||||
## def __setattr__(self, name, value):
|
||||
## if name in ('x', 'y', 'width', 'height'):
|
||||
## setattr(self.grid0, name, value)
|
||||
## setattr(self.grid1, name, value)
|
||||
|
||||
|
||||
def demo(self):
|
||||
D = Drawing(100, 100)
|
||||
g = DoubleGrid()
|
||||
D.add(g)
|
||||
return D
|
||||
|
||||
|
||||
def draw(self):
|
||||
group = Group()
|
||||
g0, g1 = self.grid0, self.grid1
|
||||
# Order groups to make sure both v and h lines
|
||||
# are visible (works only when there is only
|
||||
# one kind of stripes, v or h).
|
||||
G = g0.useRects == 1 and g1.useRects == 0 and (g0,g1) or (g1,g0)
|
||||
for g in G:
|
||||
group.add(g.makeOuterRect())
|
||||
for g in G:
|
||||
group.add(g.makeInnerTiles())
|
||||
group.add(g.makeInnerLines(),name='_gridLines')
|
||||
|
||||
return group
|
||||
|
||||
|
||||
class ShadedRect(Widget):
|
||||
"""This makes a rectangle with shaded colors between two colors.
|
||||
|
||||
Colors are interpolated linearly between 'fillColorStart'
|
||||
and 'fillColorEnd', both of which appear at the margins.
|
||||
If 'numShades' is set to one, though, only 'fillColorStart'
|
||||
is used.
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(
|
||||
x = AttrMapValue(isNumber, desc="The grid's lower-left x position."),
|
||||
y = AttrMapValue(isNumber, desc="The grid's lower-left y position."),
|
||||
width = AttrMapValue(isNumber, desc="The grid's width."),
|
||||
height = AttrMapValue(isNumber, desc="The grid's height."),
|
||||
orientation = AttrMapValue(OneOf(('vertical', 'horizontal')), desc='Determines if stripes are vertical or horizontal.'),
|
||||
numShades = AttrMapValue(isNumber, desc='The number of interpolating colors.'),
|
||||
fillColorStart = AttrMapValue(isColorOrNone, desc='Start value of the color shade.'),
|
||||
fillColorEnd = AttrMapValue(isColorOrNone, desc='End value of the color shade.'),
|
||||
strokeColor = AttrMapValue(isColorOrNone, desc='Color used for border line.'),
|
||||
strokeWidth = AttrMapValue(isNumber, desc='Width used for lines.'),
|
||||
cylinderMode = AttrMapValue(isBoolean, desc='True if shading reverses in middle.'),
|
||||
)
|
||||
|
||||
def __init__(self,**kw):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.width = 100
|
||||
self.height = 100
|
||||
self.orientation = 'vertical'
|
||||
self.numShades = 20
|
||||
self.fillColorStart = colors.pink
|
||||
self.fillColorEnd = colors.black
|
||||
self.strokeColor = colors.black
|
||||
self.strokeWidth = 2
|
||||
self.cylinderMode = 0
|
||||
self.setProperties(kw)
|
||||
|
||||
def demo(self):
|
||||
D = Drawing(100, 100)
|
||||
g = ShadedRect()
|
||||
D.add(g)
|
||||
|
||||
return D
|
||||
|
||||
def _flipRectCorners(self):
|
||||
"Flip rectangle's corners if width or height is negative."
|
||||
x, y, width, height, fillColorStart, fillColorEnd = self.x, self.y, self.width, self.height, self.fillColorStart, self.fillColorEnd
|
||||
if width < 0 and height > 0:
|
||||
x = x + width
|
||||
width = -width
|
||||
if self.orientation=='vertical': fillColorStart, fillColorEnd = fillColorEnd, fillColorStart
|
||||
elif height<0 and width>0:
|
||||
y = y + height
|
||||
height = -height
|
||||
if self.orientation=='horizontal': fillColorStart, fillColorEnd = fillColorEnd, fillColorStart
|
||||
elif height < 0 and height < 0:
|
||||
x = x + width
|
||||
width = -width
|
||||
y = y + height
|
||||
height = -height
|
||||
return x, y, width, height, fillColorStart, fillColorEnd
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
group = Group()
|
||||
x, y, w, h, c0, c1 = self._flipRectCorners()
|
||||
numShades = self.numShades
|
||||
if self.cylinderMode:
|
||||
if not numShades%2: numShades = numShades+1
|
||||
halfNumShades = int((numShades-1)/2) + 1
|
||||
num = float(numShades) # must make it float!
|
||||
vertical = self.orientation == 'vertical'
|
||||
if vertical:
|
||||
if numShades == 1:
|
||||
V = [x]
|
||||
else:
|
||||
V = frange(x, x + w, w/num)
|
||||
else:
|
||||
if numShades == 1:
|
||||
V = [y]
|
||||
else:
|
||||
V = frange(y, y + h, h/num)
|
||||
|
||||
for v in V:
|
||||
stripe = vertical and Rect(v, y, w/num, h) or Rect(x, v, w, h/num)
|
||||
if self.cylinderMode:
|
||||
if V.index(v)>=halfNumShades:
|
||||
col = colors.linearlyInterpolatedColor(c1,c0,V[halfNumShades],V[-1], v)
|
||||
else:
|
||||
col = colors.linearlyInterpolatedColor(c0,c1,V[0],V[halfNumShades], v)
|
||||
else:
|
||||
col = colors.linearlyInterpolatedColor(c0,c1,V[0],V[-1], v)
|
||||
stripe.fillColor = col
|
||||
stripe.strokeColor = col
|
||||
stripe.strokeWidth = 1
|
||||
group.add(stripe)
|
||||
if self.strokeColor and self.strokeWidth>=0:
|
||||
rect = Rect(x, y, w, h)
|
||||
rect.strokeColor = self.strokeColor
|
||||
rect.strokeWidth = self.strokeWidth
|
||||
rect.fillColor = None
|
||||
group.add(rect)
|
||||
return group
|
||||
|
||||
|
||||
def colorRange(c0, c1, n):
|
||||
"Return a range of intermediate colors between c0 and c1"
|
||||
if n==1: return [c0]
|
||||
|
||||
C = []
|
||||
if n>1:
|
||||
lim = n-1
|
||||
for i in range(n):
|
||||
C.append(colors.linearlyInterpolatedColor(c0,c1,0,lim, i))
|
||||
return C
|
||||
|
||||
|
||||
def centroid(P):
|
||||
'''compute average point of a set of points'''
|
||||
cx = 0
|
||||
cy = 0
|
||||
for x,y in P:
|
||||
cx+=x
|
||||
cy+=y
|
||||
n = float(len(P))
|
||||
return cx/n, cy/n
|
||||
|
||||
def rotatedEnclosingRect(P, angle, rect):
|
||||
'''
|
||||
given P a sequence P of x,y coordinate pairs and an angle in degrees
|
||||
find the centroid of P and the axis at angle theta through it
|
||||
find the extreme points of P wrt axis parallel distance and axis
|
||||
orthogonal distance. Then compute the least rectangle that will still
|
||||
enclose P when rotated by angle.
|
||||
|
||||
The class R
|
||||
'''
|
||||
from math import pi, cos, sin, tan
|
||||
x0, y0 = centroid(P)
|
||||
theta = (angle/180.)*pi
|
||||
s,c=sin(theta),cos(theta)
|
||||
def parallelAxisDist(xy,s=s,c=c,x0=x0,y0=y0):
|
||||
x,y = xy
|
||||
return (s*(y-y0)+c*(x-x0))
|
||||
def orthogonalAxisDist(xy,s=s,c=c,x0=x0,y0=y0):
|
||||
x,y = xy
|
||||
return (c*(y-y0)+s*(x-x0))
|
||||
L = list(map(parallelAxisDist,P))
|
||||
L.sort()
|
||||
a0, a1 = L[0], L[-1]
|
||||
L = list(map(orthogonalAxisDist,P))
|
||||
L.sort()
|
||||
b0, b1 = L[0], L[-1]
|
||||
rect.x, rect.width = a0, a1-a0
|
||||
rect.y, rect.height = b0, b1-b0
|
||||
g = Group(transform=(c,s,-s,c,x0,y0))
|
||||
g.add(rect)
|
||||
return g
|
||||
|
||||
class ShadedPolygon(Widget,LineShape):
|
||||
_attrMap = AttrMap(BASE=LineShape,
|
||||
angle = AttrMapValue(isNumber,desc="Shading angle"),
|
||||
fillColorStart = AttrMapValue(isColorOrNone),
|
||||
fillColorEnd = AttrMapValue(isColorOrNone),
|
||||
numShades = AttrMapValue(isNumber, desc='The number of interpolating colors.'),
|
||||
cylinderMode = AttrMapValue(isBoolean, desc='True if shading reverses in middle.'),
|
||||
points = AttrMapValue(isListOfNumbers),
|
||||
)
|
||||
|
||||
def __init__(self,**kw):
|
||||
self.angle = 90
|
||||
self.fillColorStart = colors.red
|
||||
self.fillColorEnd = colors.green
|
||||
self.cylinderMode = 0
|
||||
self.numShades = 50
|
||||
self.points = [-1,-1,2,2,3,-1]
|
||||
LineShape.__init__(self,kw)
|
||||
|
||||
def draw(self):
|
||||
P = self.points
|
||||
P = list(map(lambda i, P=P:(P[i],P[i+1]),range(0,len(P),2)))
|
||||
path = definePath([('moveTo',)+P[0]]+[('lineTo',)+x for x in P[1:]]+['closePath'],
|
||||
fillColor=None, strokeColor=None)
|
||||
path.isClipPath = 1
|
||||
g = Group()
|
||||
g.add(path)
|
||||
angle = self.angle
|
||||
orientation = 'vertical'
|
||||
if angle==180:
|
||||
angle = 0
|
||||
elif angle in (90,270):
|
||||
orientation ='horizontal'
|
||||
angle = 0
|
||||
rect = ShadedRect(strokeWidth=0,strokeColor=None,orientation=orientation)
|
||||
for k in 'fillColorStart', 'fillColorEnd', 'numShades', 'cylinderMode':
|
||||
setattr(rect,k,getattr(self,k))
|
||||
g.add(rotatedEnclosingRect(P, angle, rect))
|
||||
g.add(EmptyClipPath)
|
||||
path = path.copy()
|
||||
path.isClipPath = 0
|
||||
path.strokeColor = self.strokeColor
|
||||
path.strokeWidth = self.strokeWidth
|
||||
g.add(path)
|
||||
return g
|
||||
|
||||
if __name__=='__main__': #noruntests
|
||||
from reportlab.lib.colors import blue
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
angle=45
|
||||
D = Drawing(120,120)
|
||||
D.add(ShadedPolygon(points=(10,10,60,60,110,10),strokeColor=None,strokeWidth=1,angle=90,numShades=50,cylinderMode=0))
|
||||
D.save(formats=['gif'],fnRoot='shobj',outDir='/tmp')
|
||||
245
reportlab/graphics/widgets/markers.py
Normal file
245
reportlab/graphics/widgets/markers.py
Normal file
@@ -0,0 +1,245 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2013
|
||||
#see license.txt for license details
|
||||
|
||||
__version__=''' $Id$ '''
|
||||
__doc__="""This modules defines a collection of markers used in charts.
|
||||
"""
|
||||
|
||||
from reportlab.graphics.shapes import Rect, Line, Circle, Polygon, Drawing, Group
|
||||
from reportlab.graphics.widgets.signsandsymbols import SmileyFace
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
from reportlab.lib.validators import isNumber, isColorOrNone, OneOf, Validator
|
||||
from reportlab.lib.attrmap import AttrMap, AttrMapValue
|
||||
from reportlab.lib.colors import black
|
||||
from reportlab.lib.utils import isFunction, isClass
|
||||
from reportlab.graphics.widgets.flags import Flag
|
||||
from math import sin, cos, pi
|
||||
_toradians = pi/180.0
|
||||
|
||||
class Marker(Widget):
|
||||
'''A polymorphic class of markers'''
|
||||
_attrMap = AttrMap(BASE=Widget,
|
||||
kind = AttrMapValue(
|
||||
OneOf(None, 'Square', 'Diamond', 'Circle', 'Cross', 'Triangle', 'StarSix',
|
||||
'Pentagon', 'Hexagon', 'Heptagon', 'Octagon', 'StarFive',
|
||||
'FilledSquare', 'FilledCircle', 'FilledDiamond', 'FilledCross',
|
||||
'FilledTriangle','FilledStarSix', 'FilledPentagon', 'FilledHexagon',
|
||||
'FilledHeptagon', 'FilledOctagon', 'FilledStarFive',
|
||||
'Smiley','ArrowHead', 'FilledArrowHead'),
|
||||
desc='marker type name'),
|
||||
size = AttrMapValue(isNumber,desc='marker size'),
|
||||
x = AttrMapValue(isNumber,desc='marker x coordinate'),
|
||||
y = AttrMapValue(isNumber,desc='marker y coordinate'),
|
||||
dx = AttrMapValue(isNumber,desc='marker x coordinate adjustment'),
|
||||
dy = AttrMapValue(isNumber,desc='marker y coordinate adjustment'),
|
||||
angle = AttrMapValue(isNumber,desc='marker rotation'),
|
||||
fillColor = AttrMapValue(isColorOrNone, desc='marker fill colour'),
|
||||
strokeColor = AttrMapValue(isColorOrNone, desc='marker stroke colour'),
|
||||
strokeWidth = AttrMapValue(isNumber, desc='marker stroke width'),
|
||||
arrowBarbDx = AttrMapValue(isNumber, desc='arrow only the delta x for the barbs'),
|
||||
arrowHeight = AttrMapValue(isNumber, desc='arrow only height'),
|
||||
)
|
||||
|
||||
def __init__(self,*args,**kw):
|
||||
self.setProperties(kw)
|
||||
self._setKeywords(
|
||||
kind = None,
|
||||
strokeColor = black,
|
||||
strokeWidth = 0.1,
|
||||
fillColor = None,
|
||||
size = 5,
|
||||
x = 0,
|
||||
y = 0,
|
||||
dx = 0,
|
||||
dy = 0,
|
||||
angle = 0,
|
||||
arrowBarbDx = -1.25,
|
||||
arrowHeight = 1.875,
|
||||
)
|
||||
|
||||
def clone(self,**kwds):
|
||||
n = self.__class__(**self.__dict__)
|
||||
if kwds: n.__dict__.update(kwds)
|
||||
return n
|
||||
|
||||
def _Smiley(self):
|
||||
x, y = self.x+self.dx, self.y+self.dy
|
||||
d = self.size/2.0
|
||||
s = SmileyFace()
|
||||
s.fillColor = self.fillColor
|
||||
s.strokeWidth = self.strokeWidth
|
||||
s.strokeColor = self.strokeColor
|
||||
s.x = x-d
|
||||
s.y = y-d
|
||||
s.size = d*2
|
||||
return s
|
||||
|
||||
def _Square(self):
|
||||
x, y = self.x+self.dx, self.y+self.dy
|
||||
d = self.size/2.0
|
||||
s = Rect(x-d,y-d,2*d,2*d,fillColor=self.fillColor,strokeColor=self.strokeColor,strokeWidth=self.strokeWidth)
|
||||
return s
|
||||
|
||||
def _Diamond(self):
|
||||
d = self.size/2.0
|
||||
return self._doPolygon((-d,0,0,d,d,0,0,-d))
|
||||
|
||||
def _Circle(self):
|
||||
x, y = self.x+self.dx, self.y+self.dy
|
||||
s = Circle(x,y,self.size/2.0,fillColor=self.fillColor,strokeColor=self.strokeColor,strokeWidth=self.strokeWidth)
|
||||
return s
|
||||
|
||||
def _Cross(self):
|
||||
x, y = self.x+self.dx, self.y+self.dy
|
||||
s = float(self.size)
|
||||
h, s = s/2, s/6
|
||||
return self._doPolygon((-s,-h,-s,-s,-h,-s,-h,s,-s,s,-s,h,s,h,s,s,h,s,h,-s,s,-s,s,-h))
|
||||
|
||||
def _Triangle(self):
|
||||
x, y = self.x+self.dx, self.y+self.dy
|
||||
r = float(self.size)/2
|
||||
c = 30*_toradians
|
||||
s = sin(30*_toradians)*r
|
||||
c = cos(c)*r
|
||||
return self._doPolygon((0,r,-c,-s,c,-s))
|
||||
|
||||
def _StarSix(self):
|
||||
r = float(self.size)/2
|
||||
c = 30*_toradians
|
||||
s = sin(c)*r
|
||||
c = cos(c)*r
|
||||
z = s/2
|
||||
g = c/2
|
||||
return self._doPolygon((0,r,-z,s,-c,s,-s,0,-c,-s,-z,-s,0,-r,z,-s,c,-s,s,0,c,s,z,s))
|
||||
|
||||
def _StarFive(self):
|
||||
R = float(self.size)/2
|
||||
r = R*sin(18*_toradians)/cos(36*_toradians)
|
||||
P = []
|
||||
angle = 90
|
||||
for i in range(5):
|
||||
for radius in R, r:
|
||||
theta = angle*_toradians
|
||||
P.append(radius*cos(theta))
|
||||
P.append(radius*sin(theta))
|
||||
angle = angle + 36
|
||||
return self._doPolygon(P)
|
||||
|
||||
def _Pentagon(self):
|
||||
return self._doNgon(5)
|
||||
|
||||
def _Hexagon(self):
|
||||
return self._doNgon(6)
|
||||
|
||||
def _Heptagon(self):
|
||||
return self._doNgon(7)
|
||||
|
||||
def _Octagon(self):
|
||||
return self._doNgon(8)
|
||||
|
||||
def _ArrowHead(self):
|
||||
s = self.size
|
||||
h = self.arrowHeight
|
||||
b = self.arrowBarbDx
|
||||
return self._doPolygon((0,0,b,-h,s,0,b,h))
|
||||
|
||||
def _doPolygon(self,P):
|
||||
x, y = self.x+self.dx, self.y+self.dy
|
||||
if x or y: P = list(map(lambda i,P=P,A=[x,y]: P[i] + A[i&1], list(range(len(P)))))
|
||||
return Polygon(P, strokeWidth =self.strokeWidth, strokeColor=self.strokeColor, fillColor=self.fillColor)
|
||||
|
||||
def _doFill(self):
|
||||
old = self.fillColor
|
||||
if old is None:
|
||||
self.fillColor = self.strokeColor
|
||||
r = (self.kind and getattr(self,'_'+self.kind[6:]) or Group)()
|
||||
self.fillColor = old
|
||||
return r
|
||||
|
||||
def _doNgon(self,n):
|
||||
P = []
|
||||
size = float(self.size)/2
|
||||
for i in range(n):
|
||||
r = (2.*i/n+0.5)*pi
|
||||
P.append(size*cos(r))
|
||||
P.append(size*sin(r))
|
||||
return self._doPolygon(P)
|
||||
|
||||
_FilledCircle = _doFill
|
||||
_FilledSquare = _doFill
|
||||
_FilledDiamond = _doFill
|
||||
_FilledCross = _doFill
|
||||
_FilledTriangle = _doFill
|
||||
_FilledStarSix = _doFill
|
||||
_FilledPentagon = _doFill
|
||||
_FilledHexagon = _doFill
|
||||
_FilledHeptagon = _doFill
|
||||
_FilledOctagon = _doFill
|
||||
_FilledStarFive = _doFill
|
||||
_FilledArrowHead = _doFill
|
||||
|
||||
def draw(self):
|
||||
if self.kind:
|
||||
m = getattr(self,'_'+self.kind)
|
||||
if self.angle:
|
||||
_x, _dx, _y, _dy = self.x, self.dx, self.y, self.dy
|
||||
self.x, self.dx, self.y, self.dy = 0,0,0,0
|
||||
try:
|
||||
m = m()
|
||||
finally:
|
||||
self.x, self.dx, self.y, self.dy = _x, _dx, _y, _dy
|
||||
if not isinstance(m,Group):
|
||||
_m, m = m, Group()
|
||||
m.add(_m)
|
||||
if self.angle: m.rotate(self.angle)
|
||||
x, y = _x+_dx, _y+_dy
|
||||
if x or y: m.shift(x,y)
|
||||
else:
|
||||
m = m()
|
||||
else:
|
||||
m = Group()
|
||||
return m
|
||||
|
||||
def uSymbol2Symbol(uSymbol,x,y,color):
|
||||
if isFunction(uSymbol):
|
||||
symbol = uSymbol(x, y, 5, color)
|
||||
elif isClass(uSymbol) and issubclass(uSymbol,Widget):
|
||||
size = 10.
|
||||
symbol = uSymbol()
|
||||
symbol.x = x - (size/2)
|
||||
symbol.y = y - (size/2)
|
||||
try:
|
||||
symbol.size = size
|
||||
symbol.color = color
|
||||
except:
|
||||
pass
|
||||
elif isinstance(uSymbol,Marker) or isinstance(uSymbol,Flag):
|
||||
symbol = uSymbol.clone()
|
||||
if isinstance(uSymbol,Marker): symbol.fillColor = symbol.fillColor or color
|
||||
symbol.x, symbol.y = x, y
|
||||
else:
|
||||
symbol = None
|
||||
return symbol
|
||||
|
||||
class _isSymbol(Validator):
|
||||
def test(self,x):
|
||||
return hasattr(x,'__call__') or isinstance(x,Marker) or isinstance(x,Flag) or (isinstance(x,type) and issubclass(x,Widget))
|
||||
|
||||
isSymbol = _isSymbol()
|
||||
|
||||
def makeMarker(name,**kw):
|
||||
if Marker._attrMap['kind'].validate(name):
|
||||
m = Marker(**kw)
|
||||
m.kind = name
|
||||
elif name[-5:]=='_Flag' and Flag._attrMap['kind'].validate(name[:-5]):
|
||||
m = Flag(**kw)
|
||||
m.kind = name[:-5]
|
||||
m.size = 10
|
||||
else:
|
||||
raise ValueError("Invalid marker name %s" % name)
|
||||
return m
|
||||
|
||||
if __name__=='__main__':
|
||||
D = Drawing()
|
||||
D.add(Marker())
|
||||
D.save(fnRoot='Marker',formats=['pdf'], outDir='/tmp')
|
||||
933
reportlab/graphics/widgets/signsandsymbols.py
Normal file
933
reportlab/graphics/widgets/signsandsymbols.py
Normal file
@@ -0,0 +1,933 @@
|
||||
#Copyright ReportLab Europe Ltd. 2000-2012
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/signsandsymbols.py
|
||||
# signsandsymbols.py
|
||||
# A collection of new widgets
|
||||
# author: John Precedo (johnp@reportlab.com)
|
||||
|
||||
__version__=''' $Id$ '''
|
||||
__doc__="""This file is a collection of widgets to produce some common signs and symbols.
|
||||
|
||||
Widgets include:
|
||||
|
||||
- ETriangle (an equilateral triangle),
|
||||
- RTriangle (a right angled triangle),
|
||||
- Octagon,
|
||||
- Crossbox,
|
||||
- Tickbox,
|
||||
- SmileyFace,
|
||||
- StopSign,
|
||||
- NoEntry,
|
||||
- NotAllowed (the red roundel from 'no smoking' signs),
|
||||
- NoSmoking,
|
||||
- DangerSign (a black exclamation point in a yellow triangle),
|
||||
- YesNo (returns a tickbox or a crossbox depending on a testvalue),
|
||||
- FloppyDisk,
|
||||
- ArrowOne, and
|
||||
- ArrowTwo
|
||||
"""
|
||||
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.validators import *
|
||||
from reportlab.lib.attrmap import *
|
||||
from reportlab.graphics import shapes
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
from reportlab.graphics import renderPDF
|
||||
|
||||
|
||||
class _Symbol(Widget):
|
||||
"""Abstract base widget
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'fillColor', 'strokeColor'
|
||||
"""
|
||||
_nodoc = 1
|
||||
_attrMap = AttrMap(
|
||||
x = AttrMapValue(isNumber,desc='symbol x coordinate'),
|
||||
y = AttrMapValue(isNumber,desc='symbol y coordinate'),
|
||||
dx = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'),
|
||||
dy = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'),
|
||||
size = AttrMapValue(isNumber),
|
||||
fillColor = AttrMapValue(isColorOrNone),
|
||||
strokeColor = AttrMapValue(isColorOrNone),
|
||||
strokeWidth = AttrMapValue(isNumber),
|
||||
)
|
||||
def __init__(self):
|
||||
assert self.__class__.__name__!='_Symbol', 'Abstract class _Symbol instantiated'
|
||||
self.x = self.y = self.dx = self.dy = 0
|
||||
self.size = 100
|
||||
self.fillColor = colors.red
|
||||
self.strokeColor = None
|
||||
self.strokeWidth = 0.1
|
||||
|
||||
def demo(self):
|
||||
D = shapes.Drawing(200, 100)
|
||||
s = float(self.size)
|
||||
ob = self.__class__()
|
||||
ob.x=50
|
||||
ob.y=0
|
||||
ob.draw()
|
||||
D.add(ob)
|
||||
D.add(shapes.String(ob.x+(s/2),(ob.y-12),
|
||||
ob.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=10))
|
||||
return D
|
||||
|
||||
class ETriangle(_Symbol):
|
||||
"""This draws an equilateral triangle."""
|
||||
|
||||
def __init__(self):
|
||||
pass #AbstractSymbol
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
# Triangle specific bits
|
||||
ae = s*0.125 #(ae = 'an eighth')
|
||||
triangle = shapes.Polygon(points = [
|
||||
self.x, self.y,
|
||||
self.x+s, self.y,
|
||||
self.x+(s/2),self.y+s],
|
||||
fillColor = self.fillColor,
|
||||
strokeColor = self.strokeColor,
|
||||
strokeWidth=s/50.)
|
||||
g.add(triangle)
|
||||
return g
|
||||
|
||||
class RTriangle(_Symbol):
|
||||
"""This draws a right-angled triangle.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'fillColor', 'strokeColor'
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.fillColor = colors.green
|
||||
self.strokeColor = None
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
# Triangle specific bits
|
||||
ae = s*0.125 #(ae = 'an eighth')
|
||||
triangle = shapes.Polygon(points = [
|
||||
self.x, self.y,
|
||||
self.x+s, self.y,
|
||||
self.x,self.y+s],
|
||||
fillColor = self.fillColor,
|
||||
strokeColor = self.strokeColor,
|
||||
strokeWidth=s/50.)
|
||||
g.add(triangle)
|
||||
return g
|
||||
|
||||
class Octagon(_Symbol):
|
||||
"""This widget draws an Octagon.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'fillColor', 'strokeColor'
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.fillColor = colors.yellow
|
||||
self.strokeColor = None
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
# Octagon specific bits
|
||||
athird=s/3
|
||||
|
||||
octagon = shapes.Polygon(points=[self.x+athird, self.y,
|
||||
self.x, self.y+athird,
|
||||
self.x, self.y+(athird*2),
|
||||
self.x+athird, self.y+s,
|
||||
self.x+(athird*2), self.y+s,
|
||||
self.x+s, self.y+(athird*2),
|
||||
self.x+s, self.y+athird,
|
||||
self.x+(athird*2), self.y],
|
||||
strokeColor = self.strokeColor,
|
||||
fillColor = self.fillColor,
|
||||
strokeWidth=10)
|
||||
g.add(octagon)
|
||||
return g
|
||||
|
||||
class Crossbox(_Symbol):
|
||||
"""This draws a black box with a red cross in it - a 'checkbox'.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'crossColor', 'strokeColor', 'crosswidth'
|
||||
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(BASE=_Symbol,
|
||||
crossColor = AttrMapValue(isColorOrNone),
|
||||
crosswidth = AttrMapValue(isNumber),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.fillColor = colors.white
|
||||
self.crossColor = colors.red
|
||||
self.strokeColor = colors.black
|
||||
self.crosswidth = 10
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
# crossbox specific bits
|
||||
box = shapes.Rect(self.x+1, self.y+1, s-2, s-2,
|
||||
fillColor = self.fillColor,
|
||||
strokeColor = self.strokeColor,
|
||||
strokeWidth=2)
|
||||
g.add(box)
|
||||
|
||||
crossLine1 = shapes.Line(self.x+(s*0.15), self.y+(s*0.15), self.x+(s*0.85), self.y+(s*0.85),
|
||||
fillColor = self.crossColor,
|
||||
strokeColor = self.crossColor,
|
||||
strokeWidth = self.crosswidth)
|
||||
g.add(crossLine1)
|
||||
|
||||
crossLine2 = shapes.Line(self.x+(s*0.15), self.y+(s*0.85), self.x+(s*0.85) ,self.y+(s*0.15),
|
||||
fillColor = self.crossColor,
|
||||
strokeColor = self.crossColor,
|
||||
strokeWidth = self.crosswidth)
|
||||
g.add(crossLine2)
|
||||
|
||||
return g
|
||||
|
||||
|
||||
class Tickbox(_Symbol):
|
||||
"""This draws a black box with a red tick in it - another 'checkbox'.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'tickColor', 'strokeColor', 'tickwidth'
|
||||
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(BASE=_Symbol,
|
||||
tickColor = AttrMapValue(isColorOrNone),
|
||||
tickwidth = AttrMapValue(isNumber),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.tickColor = colors.red
|
||||
self.strokeColor = colors.black
|
||||
self.fillColor = colors.white
|
||||
self.tickwidth = 10
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
# tickbox specific bits
|
||||
box = shapes.Rect(self.x+1, self.y+1, s-2, s-2,
|
||||
fillColor = self.fillColor,
|
||||
strokeColor = self.strokeColor,
|
||||
strokeWidth=2)
|
||||
g.add(box)
|
||||
|
||||
tickLine = shapes.PolyLine(points = [self.x+(s*0.15), self.y+(s*0.35), self.x+(s*0.35), self.y+(s*0.15),
|
||||
self.x+(s*0.35), self.y+(s*0.15), self.x+(s*0.85) ,self.y+(s*0.85)],
|
||||
fillColor = self.tickColor,
|
||||
strokeColor = self.tickColor,
|
||||
strokeWidth = self.tickwidth)
|
||||
g.add(tickLine)
|
||||
|
||||
return g
|
||||
|
||||
class SmileyFace(_Symbol):
|
||||
"""This draws a classic smiley face.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'fillColor'
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
_Symbol.__init__(self)
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.fillColor = colors.yellow
|
||||
self.strokeColor = colors.black
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
# SmileyFace specific bits
|
||||
g.add(shapes.Circle(cx=self.x+(s/2), cy=self.y+(s/2), r=s/2,
|
||||
fillColor=self.fillColor, strokeColor=self.strokeColor,
|
||||
strokeWidth=max(s/38.,self.strokeWidth)))
|
||||
|
||||
for i in (1,2):
|
||||
g.add(shapes.Ellipse(self.x+(s/3)*i,self.y+(s/3)*2, s/30, s/10,
|
||||
fillColor=self.strokeColor, strokeColor = self.strokeColor,
|
||||
strokeWidth=max(s/38.,self.strokeWidth)))
|
||||
|
||||
# calculate a pointslist for the mouth
|
||||
# THIS IS A HACK! - don't use if there is a 'shapes.Arc'
|
||||
centerx=self.x+(s/2)
|
||||
centery=self.y+(s/2)
|
||||
radius=s/3
|
||||
yradius = radius
|
||||
xradius = radius
|
||||
startangledegrees=200
|
||||
endangledegrees=340
|
||||
degreedelta = 1
|
||||
pointslist = []
|
||||
a = pointslist.append
|
||||
from math import sin, cos, pi
|
||||
degreestoradians = pi/180.0
|
||||
radiansdelta = degreedelta*degreestoradians
|
||||
startangle = startangledegrees*degreestoradians
|
||||
endangle = endangledegrees*degreestoradians
|
||||
while endangle<startangle:
|
||||
endangle = endangle+2*pi
|
||||
angle = startangle
|
||||
while angle<endangle:
|
||||
x = centerx + cos(angle)*radius
|
||||
y = centery + sin(angle)*yradius
|
||||
a(x); a(y)
|
||||
angle = angle+radiansdelta
|
||||
|
||||
# make the mouth
|
||||
smile = shapes.PolyLine(pointslist,
|
||||
fillColor = self.strokeColor,
|
||||
strokeColor = self.strokeColor,
|
||||
strokeWidth = max(s/38.,self.strokeWidth))
|
||||
g.add(smile)
|
||||
|
||||
return g
|
||||
|
||||
class StopSign(_Symbol):
|
||||
"""This draws a (British) stop sign.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size'
|
||||
|
||||
"""
|
||||
_attrMap = AttrMap(BASE=_Symbol,
|
||||
stopColor = AttrMapValue(isColorOrNone,desc='color of the word stop'),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.strokeColor = colors.black
|
||||
self.fillColor = colors.orangered
|
||||
self.stopColor = colors.ghostwhite
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
# stop-sign specific bits
|
||||
athird=s/3
|
||||
|
||||
outerOctagon = shapes.Polygon(points=[self.x+athird, self.y,
|
||||
self.x, self.y+athird,
|
||||
self.x, self.y+(athird*2),
|
||||
self.x+athird, self.y+s,
|
||||
self.x+(athird*2), self.y+s,
|
||||
self.x+s, self.y+(athird*2),
|
||||
self.x+s, self.y+athird,
|
||||
self.x+(athird*2), self.y],
|
||||
strokeColor = self.strokeColor,
|
||||
fillColor = None,
|
||||
strokeWidth=1)
|
||||
g.add(outerOctagon)
|
||||
|
||||
innerOctagon = shapes.Polygon(points=[self.x+athird+(s/75), self.y+(s/75),
|
||||
self.x+(s/75), self.y+athird+(s/75),
|
||||
self.x+(s/75), self.y+(athird*2)-(s/75),
|
||||
self.x+athird+(s/75), self.y+s-(s/75),
|
||||
self.x+(athird*2)-(s/75), (self.y+s)-(s/75),
|
||||
(self.x+s)-(s/75), self.y+(athird*2)-(s/75),
|
||||
(self.x+s)-(s/75), self.y+athird+(s/75),
|
||||
self.x+(athird*2)-(s/75), self.y+(s/75)],
|
||||
strokeColor = None,
|
||||
fillColor = self.fillColor,
|
||||
strokeWidth=0)
|
||||
g.add(innerOctagon)
|
||||
|
||||
if self.stopColor:
|
||||
g.add(shapes.String(self.x+(s*0.5),self.y+(s*0.4),
|
||||
'STOP', fillColor=self.stopColor, textAnchor='middle',
|
||||
fontSize=s/3, fontName="Helvetica-Bold"))
|
||||
|
||||
return g
|
||||
|
||||
|
||||
class NoEntry(_Symbol):
|
||||
"""This draws a (British) No Entry sign - a red circle with a white line on it.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size'
|
||||
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(BASE=_Symbol,
|
||||
innerBarColor = AttrMapValue(isColorOrNone,desc='color of the inner bar'),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.strokeColor = colors.black
|
||||
self.fillColor = colors.orangered
|
||||
self.innerBarColor = colors.ghostwhite
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
# no-entry-sign specific bits
|
||||
if self.strokeColor:
|
||||
g.add(shapes.Circle(cx = (self.x+(s/2)), cy = (self.y+(s/2)), r = s/2, fillColor = None, strokeColor = self.strokeColor, strokeWidth=1))
|
||||
|
||||
if self.fillColor:
|
||||
g.add(shapes.Circle(cx = (self.x+(s/2)), cy =(self.y+(s/2)), r = ((s/2)-(s/50)), fillColor = self.fillColor, strokeColor = None, strokeWidth=0))
|
||||
|
||||
innerBarColor = self.innerBarColor
|
||||
if innerBarColor:
|
||||
g.add(shapes.Rect(self.x+(s*0.1), self.y+(s*0.4), width=s*0.8, height=s*0.2, fillColor = innerBarColor, strokeColor = innerBarColor, strokeLineCap = 1, strokeWidth = 0))
|
||||
return g
|
||||
|
||||
class NotAllowed(_Symbol):
|
||||
"""This draws a 'forbidden' roundel (as used in the no-smoking sign).
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size'
|
||||
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(BASE=_Symbol,
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.strokeColor = colors.red
|
||||
self.fillColor = colors.white
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
strokeColor = self.strokeColor
|
||||
|
||||
# not=allowed specific bits
|
||||
outerCircle = shapes.Circle(cx = (self.x+(s/2)), cy = (self.y+(s/2)), r = (s/2)-(s/10), fillColor = self.fillColor, strokeColor = strokeColor, strokeWidth=s/10.)
|
||||
g.add(outerCircle)
|
||||
|
||||
centerx=self.x+s
|
||||
centery=self.y+(s/2)-(s/6)
|
||||
radius=s-(s/6)
|
||||
yradius = radius/2
|
||||
xradius = radius/2
|
||||
startangledegrees=100
|
||||
endangledegrees=-80
|
||||
degreedelta = 90
|
||||
pointslist = []
|
||||
a = pointslist.append
|
||||
from math import sin, cos, pi
|
||||
degreestoradians = pi/180.0
|
||||
radiansdelta = degreedelta*degreestoradians
|
||||
startangle = startangledegrees*degreestoradians
|
||||
endangle = endangledegrees*degreestoradians
|
||||
while endangle<startangle:
|
||||
endangle = endangle+2*pi
|
||||
angle = startangle
|
||||
while angle<endangle:
|
||||
x = centerx + cos(angle)*radius
|
||||
y = centery + sin(angle)*yradius
|
||||
a(x); a(y)
|
||||
angle = angle+radiansdelta
|
||||
crossbar = shapes.PolyLine(pointslist, fillColor = strokeColor, strokeColor = strokeColor, strokeWidth = s/10.)
|
||||
g.add(crossbar)
|
||||
return g
|
||||
|
||||
|
||||
class NoSmoking(NotAllowed):
|
||||
"""This draws a no-smoking sign.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size'
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
NotAllowed.__init__(self)
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = NotAllowed.draw(self)
|
||||
|
||||
# no-smoking-sign specific bits
|
||||
newx = self.x+(s/2)-(s/3.5)
|
||||
newy = self.y+(s/2)-(s/32)
|
||||
cigarrette1 = shapes.Rect(x = newx, y = newy, width = (s/2), height =(s/16),
|
||||
fillColor = colors.ghostwhite, strokeColor = colors.gray, strokeWidth=0)
|
||||
newx=newx+(s/2)+(s/64)
|
||||
g.insert(-1,cigarrette1)
|
||||
|
||||
cigarrette2 = shapes.Rect(x = newx, y = newy, width = (s/80), height =(s/16),
|
||||
fillColor = colors.orangered, strokeColor = None, strokeWidth=0)
|
||||
newx= newx+(s/35)
|
||||
g.insert(-1,cigarrette2)
|
||||
|
||||
cigarrette3 = shapes.Rect(x = newx, y = newy, width = (s/80), height =(s/16),
|
||||
fillColor = colors.orangered, strokeColor = None, strokeWidth=0)
|
||||
newx= newx+(s/35)
|
||||
g.insert(-1,cigarrette3)
|
||||
|
||||
cigarrette4 = shapes.Rect(x = newx, y = newy, width = (s/80), height =(s/16),
|
||||
fillColor = colors.orangered, strokeColor = None, strokeWidth=0)
|
||||
newx= newx+(s/35)
|
||||
g.insert(-1,cigarrette4)
|
||||
|
||||
return g
|
||||
|
||||
|
||||
class DangerSign(_Symbol):
|
||||
"""This draws a 'danger' sign: a yellow box with a black exclamation point.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'strokeColor', 'fillColor', 'strokeWidth'
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.strokeColor = colors.black
|
||||
self.fillColor = colors.gold
|
||||
self.strokeWidth = self.size*0.125
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
ew = self.strokeWidth
|
||||
ae = s*0.125 #(ae = 'an eighth')
|
||||
|
||||
|
||||
# danger sign specific bits
|
||||
|
||||
ew = self.strokeWidth
|
||||
ae = s*0.125 #(ae = 'an eighth')
|
||||
|
||||
outerTriangle = shapes.Polygon(points = [
|
||||
self.x, self.y,
|
||||
self.x+s, self.y,
|
||||
self.x+(s/2),self.y+s],
|
||||
fillColor = None,
|
||||
strokeColor = self.strokeColor,
|
||||
strokeWidth=0)
|
||||
g.add(outerTriangle)
|
||||
|
||||
innerTriangle = shapes.Polygon(points = [
|
||||
self.x+(s/50), self.y+(s/75),
|
||||
(self.x+s)-(s/50), self.y+(s/75),
|
||||
self.x+(s/2),(self.y+s)-(s/50)],
|
||||
fillColor = self.fillColor,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(innerTriangle)
|
||||
|
||||
exmark = shapes.Polygon(points=[
|
||||
((self.x+s/2)-ew/2), self.y+ae*2.5,
|
||||
((self.x+s/2)+ew/2), self.y+ae*2.5,
|
||||
((self.x+s/2)+((ew/2))+(ew/6)), self.y+ae*5.5,
|
||||
((self.x+s/2)-((ew/2))-(ew/6)), self.y+ae*5.5],
|
||||
fillColor = self.strokeColor,
|
||||
strokeColor = None)
|
||||
g.add(exmark)
|
||||
|
||||
exdot = shapes.Polygon(points=[
|
||||
((self.x+s/2)-ew/2), self.y+ae,
|
||||
((self.x+s/2)+ew/2), self.y+ae,
|
||||
((self.x+s/2)+ew/2), self.y+ae*2,
|
||||
((self.x+s/2)-ew/2), self.y+ae*2],
|
||||
fillColor = self.strokeColor,
|
||||
strokeColor = None)
|
||||
g.add(exdot)
|
||||
|
||||
return g
|
||||
|
||||
|
||||
class YesNo(_Symbol):
|
||||
"""This widget draw a tickbox or crossbox depending on 'testValue'.
|
||||
|
||||
If this widget is supplied with a 'True' or 1 as a value for
|
||||
testValue, it will use the tickbox widget. Otherwise, it will
|
||||
produce a crossbox.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'tickcolor', 'crosscolor', 'testValue'
|
||||
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(BASE=_Symbol,
|
||||
tickcolor = AttrMapValue(isColor),
|
||||
crosscolor = AttrMapValue(isColor),
|
||||
testValue = AttrMapValue(isBoolean),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.tickcolor = colors.green
|
||||
self.crosscolor = colors.red
|
||||
self.testValue = 1
|
||||
|
||||
def draw(self):
|
||||
if self.testValue:
|
||||
yn=Tickbox()
|
||||
yn.tickColor=self.tickcolor
|
||||
else:
|
||||
yn=Crossbox()
|
||||
yn.crossColor=self.crosscolor
|
||||
yn.x=self.x
|
||||
yn.y=self.y
|
||||
yn.size=self.size
|
||||
yn.draw()
|
||||
return yn
|
||||
|
||||
|
||||
def demo(self):
|
||||
D = shapes.Drawing(200, 100)
|
||||
yn = YesNo()
|
||||
yn.x = 15
|
||||
yn.y = 25
|
||||
yn.size = 70
|
||||
yn.testValue = 0
|
||||
yn.draw()
|
||||
D.add(yn)
|
||||
yn2 = YesNo()
|
||||
yn2.x = 120
|
||||
yn2.y = 25
|
||||
yn2.size = 70
|
||||
yn2.testValue = 1
|
||||
yn2.draw()
|
||||
D.add(yn2)
|
||||
labelFontSize = 8
|
||||
D.add(shapes.String(yn.x+(yn.size/2),(yn.y-(1.2*labelFontSize)),
|
||||
'testValue=0', fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
D.add(shapes.String(yn2.x+(yn2.size/2),(yn2.y-(1.2*labelFontSize)),
|
||||
'testValue=1', fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
labelFontSize = 10
|
||||
D.add(shapes.String(yn.x+85,(yn.y-20),
|
||||
self.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
return D
|
||||
|
||||
class FloppyDisk(_Symbol):
|
||||
"""This widget draws an icon of a floppy disk.
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'diskcolor'
|
||||
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(BASE=_Symbol,
|
||||
diskColor = AttrMapValue(isColor),
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.diskColor = colors.black
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
|
||||
# floppy disk specific bits
|
||||
diskBody = shapes.Rect(x=self.x, y=self.y+(s/100), width=s, height=s-(s/100),
|
||||
fillColor = self.diskColor,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(diskBody)
|
||||
|
||||
label = shapes.Rect(x=self.x+(s*0.1), y=(self.y+s)-(s*0.5), width=s*0.8, height=s*0.48,
|
||||
fillColor = colors.whitesmoke,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(label)
|
||||
|
||||
labelsplash = shapes.Rect(x=self.x+(s*0.1), y=(self.y+s)-(s*0.1), width=s*0.8, height=s*0.08,
|
||||
fillColor = colors.royalblue,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(labelsplash)
|
||||
|
||||
|
||||
line1 = shapes.Line(x1=self.x+(s*0.15), y1=self.y+(0.6*s), x2=self.x+(s*0.85), y2=self.y+(0.6*s),
|
||||
fillColor = colors.black,
|
||||
strokeColor = colors.black,
|
||||
strokeWidth=0)
|
||||
g.add(line1)
|
||||
|
||||
line2 = shapes.Line(x1=self.x+(s*0.15), y1=self.y+(0.7*s), x2=self.x+(s*0.85), y2=self.y+(0.7*s),
|
||||
fillColor = colors.black,
|
||||
strokeColor = colors.black,
|
||||
strokeWidth=0)
|
||||
g.add(line2)
|
||||
|
||||
line3 = shapes.Line(x1=self.x+(s*0.15), y1=self.y+(0.8*s), x2=self.x+(s*0.85), y2=self.y+(0.8*s),
|
||||
fillColor = colors.black,
|
||||
strokeColor = colors.black,
|
||||
strokeWidth=0)
|
||||
g.add(line3)
|
||||
|
||||
metalcover = shapes.Rect(x=self.x+(s*0.2), y=(self.y), width=s*0.5, height=s*0.35,
|
||||
fillColor = colors.silver,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(metalcover)
|
||||
|
||||
coverslot = shapes.Rect(x=self.x+(s*0.28), y=(self.y)+(s*0.035), width=s*0.12, height=s*0.28,
|
||||
fillColor = self.diskColor,
|
||||
strokeColor = None,
|
||||
strokeWidth=0)
|
||||
g.add(coverslot)
|
||||
|
||||
return g
|
||||
|
||||
class ArrowOne(_Symbol):
|
||||
"""This widget draws an arrow (style one).
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'fillColor'
|
||||
|
||||
"""
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.fillColor = colors.red
|
||||
self.strokeWidth = 0
|
||||
self.strokeColor = None
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
x = self.x
|
||||
y = self.y
|
||||
s2 = s/2
|
||||
s3 = s/3
|
||||
s5 = s/5
|
||||
g.add(shapes.Polygon(points = [
|
||||
x,y+s3,
|
||||
x,y+2*s3,
|
||||
x+s2,y+2*s3,
|
||||
x+s2,y+4*s5,
|
||||
x+s,y+s2,
|
||||
x+s2,y+s5,
|
||||
x+s2,y+s3,
|
||||
],
|
||||
fillColor = self.fillColor,
|
||||
strokeColor = self.strokeColor,
|
||||
strokeWidth = self.strokeWidth,
|
||||
)
|
||||
)
|
||||
return g
|
||||
|
||||
class ArrowTwo(ArrowOne):
|
||||
"""This widget draws an arrow (style two).
|
||||
|
||||
possible attributes:
|
||||
'x', 'y', 'size', 'fillColor'
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.size = 100
|
||||
self.fillColor = colors.blue
|
||||
self.strokeWidth = 0
|
||||
self.strokeColor = None
|
||||
|
||||
def draw(self):
|
||||
# general widget bits
|
||||
s = float(self.size) # abbreviate as we will use this a lot
|
||||
g = shapes.Group()
|
||||
|
||||
# arrow specific bits
|
||||
x = self.x
|
||||
y = self.y
|
||||
s2 = s/2
|
||||
s3 = s/3
|
||||
s5 = s/5
|
||||
s24 = s/24
|
||||
|
||||
g.add(shapes.Polygon(
|
||||
points = [
|
||||
x,y+11*s24,
|
||||
x,y+13*s24,
|
||||
x+18.75*s24, y+13*s24,
|
||||
x+2*s3, y+2*s3,
|
||||
x+s, y+s2,
|
||||
x+2*s3, y+s3,
|
||||
x+18.75*s24, y+11*s24,
|
||||
],
|
||||
fillColor = self.fillColor,
|
||||
strokeColor = self.strokeColor,
|
||||
strokeWidth = self.strokeWidth)
|
||||
)
|
||||
|
||||
return g
|
||||
|
||||
|
||||
def test():
|
||||
"""This function produces a pdf with examples of all the signs and symbols from this file.
|
||||
"""
|
||||
labelFontSize = 10
|
||||
D = shapes.Drawing(450,650)
|
||||
cb = Crossbox()
|
||||
cb.x = 20
|
||||
cb.y = 530
|
||||
D.add(cb)
|
||||
D.add(shapes.String(cb.x+(cb.size/2),(cb.y-(1.2*labelFontSize)),
|
||||
cb.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
tb = Tickbox()
|
||||
tb.x = 170
|
||||
tb.y = 530
|
||||
D.add(tb)
|
||||
D.add(shapes.String(tb.x+(tb.size/2),(tb.y-(1.2*labelFontSize)),
|
||||
tb.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
|
||||
yn = YesNo()
|
||||
yn.x = 320
|
||||
yn.y = 530
|
||||
D.add(yn)
|
||||
tempstring = yn.__class__.__name__ + '*'
|
||||
D.add(shapes.String(yn.x+(tb.size/2),(yn.y-(1.2*labelFontSize)),
|
||||
tempstring, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
D.add(shapes.String(130,6,
|
||||
"(The 'YesNo' widget returns a tickbox if testvalue=1, and a crossbox if testvalue=0)", fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize*0.75))
|
||||
|
||||
|
||||
ss = StopSign()
|
||||
ss.x = 20
|
||||
ss.y = 400
|
||||
D.add(ss)
|
||||
D.add(shapes.String(ss.x+(ss.size/2), ss.y-(1.2*labelFontSize),
|
||||
ss.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
ne = NoEntry()
|
||||
ne.x = 170
|
||||
ne.y = 400
|
||||
D.add(ne)
|
||||
D.add(shapes.String(ne.x+(ne.size/2),(ne.y-(1.2*labelFontSize)),
|
||||
ne.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
sf = SmileyFace()
|
||||
sf.x = 320
|
||||
sf.y = 400
|
||||
D.add(sf)
|
||||
D.add(shapes.String(sf.x+(sf.size/2),(sf.y-(1.2*labelFontSize)),
|
||||
sf.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
ds = DangerSign()
|
||||
ds.x = 20
|
||||
ds.y = 270
|
||||
D.add(ds)
|
||||
D.add(shapes.String(ds.x+(ds.size/2),(ds.y-(1.2*labelFontSize)),
|
||||
ds.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
na = NotAllowed()
|
||||
na.x = 170
|
||||
na.y = 270
|
||||
D.add(na)
|
||||
D.add(shapes.String(na.x+(na.size/2),(na.y-(1.2*labelFontSize)),
|
||||
na.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
ns = NoSmoking()
|
||||
ns.x = 320
|
||||
ns.y = 270
|
||||
D.add(ns)
|
||||
D.add(shapes.String(ns.x+(ns.size/2),(ns.y-(1.2*labelFontSize)),
|
||||
ns.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
a1 = ArrowOne()
|
||||
a1.x = 20
|
||||
a1.y = 140
|
||||
D.add(a1)
|
||||
D.add(shapes.String(a1.x+(a1.size/2),(a1.y-(1.2*labelFontSize)),
|
||||
a1.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
a2 = ArrowTwo()
|
||||
a2.x = 170
|
||||
a2.y = 140
|
||||
D.add(a2)
|
||||
D.add(shapes.String(a2.x+(a2.size/2),(a2.y-(1.2*labelFontSize)),
|
||||
a2.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
fd = FloppyDisk()
|
||||
fd.x = 320
|
||||
fd.y = 140
|
||||
D.add(fd)
|
||||
D.add(shapes.String(fd.x+(fd.size/2),(fd.y-(1.2*labelFontSize)),
|
||||
fd.__class__.__name__, fillColor=colors.black, textAnchor='middle',
|
||||
fontSize=labelFontSize))
|
||||
|
||||
renderPDF.drawToFile(D, 'signsandsymbols.pdf', 'signsandsymbols.py')
|
||||
print('wrote file: signsandsymbols.pdf')
|
||||
|
||||
if __name__=='__main__':
|
||||
test()
|
||||
161
reportlab/graphics/widgets/table.py
Normal file
161
reportlab/graphics/widgets/table.py
Normal file
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python
|
||||
#Copyright ReportLab Europe Ltd. 2000-2012
|
||||
#see license.txt for license details
|
||||
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/grids.py
|
||||
__version__=''' $Id$ '''
|
||||
|
||||
from reportlab.graphics.widgetbase import Widget
|
||||
from reportlab.graphics.charts.textlabels import Label
|
||||
from reportlab.graphics import shapes
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.validators import *
|
||||
from reportlab.lib.attrmap import *
|
||||
|
||||
from reportlab.graphics.shapes import Drawing
|
||||
|
||||
class TableWidget(Widget):
|
||||
"""A two dimensions table of labels
|
||||
"""
|
||||
|
||||
_attrMap = AttrMap(
|
||||
x = AttrMapValue(isNumber, desc="x position of left edge of table"),
|
||||
y = AttrMapValue(isNumber, desc="y position of bottom edge of table"),
|
||||
width = AttrMapValue(isNumber, desc="table width"),
|
||||
height = AttrMapValue(isNumber, desc="table height"),
|
||||
borderStrokeColor = AttrMapValue(isColorOrNone, desc="table border color"),
|
||||
fillColor = AttrMapValue(isColorOrNone, desc="table fill color"),
|
||||
borderStrokeWidth = AttrMapValue(isNumber, desc="border line width"),
|
||||
horizontalDividerStrokeColor = AttrMapValue(isColorOrNone, desc="table inner horizontal lines color"),
|
||||
verticalDividerStrokeColor = AttrMapValue(isColorOrNone, desc="table inner vertical lines color"),
|
||||
horizontalDividerStrokeWidth = AttrMapValue(isNumber, desc="table inner horizontal lines width"),
|
||||
verticalDividerStrokeWidth = AttrMapValue(isNumber, desc="table inner vertical lines width"),
|
||||
dividerDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array for dividerLines.'),
|
||||
data = AttrMapValue(None, desc="a list of list of strings to be displayed in the cells"),
|
||||
boxAnchor = AttrMapValue(isBoxAnchor, desc="location of the table anchoring point"),
|
||||
fontName = AttrMapValue(isString, desc="text font in the table"),
|
||||
fontSize = AttrMapValue(isNumber, desc="font size of the table"),
|
||||
fontColor = AttrMapValue(isColorOrNone, desc="font color"),
|
||||
alignment = AttrMapValue(OneOf("left", "right"), desc="Alignment of text within cells"),
|
||||
textAnchor = AttrMapValue(OneOf('start','middle','end','numeric'), desc="Alignment of text within cells"),
|
||||
)
|
||||
|
||||
def __init__(self, x=10, y=10, **kw):
|
||||
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = 200
|
||||
self.height = 100
|
||||
self.borderStrokeColor = colors.black
|
||||
self.fillColor = None
|
||||
self.borderStrokeWidth = 0.5
|
||||
self.horizontalDividerStrokeColor = colors.black
|
||||
self.verticalDividerStrokeColor = colors.black
|
||||
self.horizontalDividerStrokeWidth = 0.5
|
||||
self.verticalDividerStrokeWidth = 0.25
|
||||
self.dividerDashArray = None
|
||||
self.data = [['North','South','East','West'],[100,110,120,130],['A','B','C','D']] # list of rows each row is a list of columns
|
||||
self.boxAnchor = 'nw'
|
||||
#self.fontName = None
|
||||
self.fontSize = 8
|
||||
self.fontColor = colors.black
|
||||
self.alignment = 'right'
|
||||
self.textAnchor = 'start'
|
||||
|
||||
|
||||
for k, v in kw.items():
|
||||
if k in list(self.__class__._attrMap.keys()):
|
||||
setattr(self, k, v)
|
||||
else:
|
||||
raise ValueError('invalid argument supplied for class %s'%self.__class__)
|
||||
|
||||
def demo(self):
|
||||
""" returns a sample of this widget with data
|
||||
"""
|
||||
d = Drawing(400, 200)
|
||||
t = TableWidget()
|
||||
d.add(t, name='table')
|
||||
d.table.dividerDashArray = (1, 3, 2)
|
||||
d.table.verticalDividerStrokeColor = None
|
||||
d.table.borderStrokeWidth = 0
|
||||
d.table.borderStrokeColor = colors.red
|
||||
return d
|
||||
|
||||
def draw(self):
|
||||
""" returns a group of shapes
|
||||
"""
|
||||
g = shapes.Group()
|
||||
|
||||
#overall border and fill
|
||||
if self.borderStrokeColor or self.fillColor: # adds border and filling color
|
||||
rect = shapes.Rect(self.x, self.y, self.width, self.height)
|
||||
rect.fillColor = self.fillColor
|
||||
rect.strokeColor = self.borderStrokeColor
|
||||
rect.strokeWidth = self.borderStrokeWidth
|
||||
g.add(rect)
|
||||
|
||||
#special case - for an empty table we want to avoid divide-by-zero
|
||||
data = self.preProcessData(self.data)
|
||||
rows = len(self.data)
|
||||
cols = len(self.data[0])
|
||||
#print "(rows,cols)=(%s, %s)"%(rows,cols)
|
||||
row_step = self.height / float(rows)
|
||||
col_step = self.width / float(cols)
|
||||
#print "(row_step,col_step)=(%s, %s)"%(row_step,col_step)
|
||||
# draw the grid
|
||||
if self.horizontalDividerStrokeColor:
|
||||
for i in range(rows): # make horizontal lines
|
||||
x1 = self.x
|
||||
x2 = self.x + self.width
|
||||
y = self.y + row_step*i
|
||||
#print 'line (%s, %s), (%s, %s)'%(x1, y, x2, y)
|
||||
line = shapes.Line(x1, y, x2, y)
|
||||
line.strokeDashArray = self.dividerDashArray
|
||||
line.strokeWidth = self.horizontalDividerStrokeWidth
|
||||
line.strokeColor = self.horizontalDividerStrokeColor
|
||||
g.add(line)
|
||||
if self.verticalDividerStrokeColor:
|
||||
for i in range(cols): # make vertical lines
|
||||
x = self.x+col_step*i
|
||||
y1 = self.y
|
||||
y2 = self.y + self.height
|
||||
#print 'line (%s, %s), (%s, %s)'%(x, y1, x, y2)
|
||||
line = shapes.Line(x, y1, x, y2)
|
||||
line.strokeDashArray = self.dividerDashArray
|
||||
line.strokeWidth = self.verticalDividerStrokeWidth
|
||||
line.strokeColor = self.verticalDividerStrokeColor
|
||||
g.add(line)
|
||||
|
||||
# since we plot data from down up, we reverse the list
|
||||
self.data.reverse()
|
||||
for (j, row) in enumerate(self.data):
|
||||
y = self.y + j*row_step + 0.5*row_step - 0.5 * self.fontSize
|
||||
for (i, datum) in enumerate(row):
|
||||
if datum:
|
||||
x = self.x + i*col_step + 0.5*col_step
|
||||
s = shapes.String(x, y, str(datum), textAnchor=self.textAnchor)
|
||||
s.fontName = self.fontName
|
||||
s.fontSize = self.fontSize
|
||||
s.fillColor = self.fontColor
|
||||
g.add(s)
|
||||
return g
|
||||
|
||||
def preProcessData(self, data):
|
||||
"""preprocess and return a new array with at least one row
|
||||
and column (use a None) if needed, and all rows the same
|
||||
length (adding Nones if needed)
|
||||
|
||||
"""
|
||||
if not data:
|
||||
return [[None]]
|
||||
#make all rows have similar number of cells, append None when needed
|
||||
max_row = max( [len(x) for x in data] )
|
||||
for rowNo, row in enumerate(data):
|
||||
if len(row) < max_row:
|
||||
row.extend([None]*(max_row-len(row)))
|
||||
return data
|
||||
|
||||
#test
|
||||
if __name__ == '__main__':
|
||||
d = TableWidget().demo()
|
||||
import os
|
||||
d.save(formats=['pdf'],outDir=os.getcwd(),fnRoot=None)
|
||||
Reference in New Issue
Block a user