prevent double call of _cleanup, which harms usefiles (and is a bad idea in general)
[PyX.git] / pyx / style.py
blob54335a8b0b25b1f7215a46af02610a4126cdf8bd
1 # -*- encoding: utf-8 -*-
4 # Copyright (C) 2002-2012 Jörg Lehmann <joergl@users.sourceforge.net>
5 # Copyright (C) 2003-2006 Michael Schindler <m-schindler@users.sourceforge.net>
6 # Copyright (C) 2002-2012 André Wobst <wobsta@users.sourceforge.net>
8 # This file is part of PyX (http://pyx.sourceforge.net/).
10 # PyX is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # PyX is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with PyX; if not, write to the Free Software
22 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 import math
25 from . import attr, unit
28 # base classes for stroke and fill styles
31 class style:
32 pass
34 class strokestyle(style):
35 pass
37 class fillstyle(style):
38 pass
41 # common stroke styles
45 class linecap(attr.exclusiveattr, strokestyle):
47 """linecap of paths"""
49 def __init__(self, value=0):
50 attr.exclusiveattr.__init__(self, linecap)
51 self.value = value
53 def processPS(self, file, writer, context, registry):
54 file.write("%d setlinecap\n" % self.value)
56 def processPDF(self, file, writer, context, registry):
57 file.write("%d J\n" % self.value)
59 def processSVGattrs(self, attrs, writer, context, registry):
60 attrs["stroke-linecap"] = {0: "butt", 1: "round", 2: "square"}[self.value]
63 linecap.butt = linecap(0)
64 linecap.round = linecap(1)
65 linecap.square = linecap(2)
66 linecap.clear = attr.clearclass(linecap)
69 class linejoin(attr.exclusiveattr, strokestyle):
71 """linejoin of paths"""
73 def __init__(self, value=0):
74 attr.exclusiveattr.__init__(self, linejoin)
75 self.value = value
77 def processPS(self, file, writer, context, registry):
78 file.write("%d setlinejoin\n" % self.value)
80 def processPDF(self, file, writer, context, registry):
81 file.write("%d j\n" % self.value)
83 def processSVGattrs(self, attrs, writer, context, registry):
84 attrs["stroke-linejoin"] = {0: "miter", 1: "round", 2: "bevel"}[self.value]
86 linejoin.miter = linejoin(0)
87 linejoin.round = linejoin(1)
88 linejoin.bevel = linejoin(2)
89 linejoin.clear = attr.clearclass(linejoin)
92 class miterlimit(attr.exclusiveattr, strokestyle):
94 """miterlimit of paths"""
96 def __init__(self, value=10.0):
97 attr.exclusiveattr.__init__(self, miterlimit)
98 self.value = value
100 def processPS(self, file, writer, context, registry):
101 file.write("%f setmiterlimit\n" % self.value)
103 def processPDF(self, file, writer, context, registry):
104 file.write("%f M\n" % self.value)
106 def processSVGattrs(self, attrs, writer, context, registry):
107 attrs["stroke-miterlimit"] = "%f" % self.value
109 miterlimit.lessthan180deg = miterlimit(1/math.sin(math.pi*180/360))
110 miterlimit.lessthan90deg = miterlimit(1/math.sin(math.pi*90/360))
111 miterlimit.lessthan60deg = miterlimit(1/math.sin(math.pi*60/360))
112 miterlimit.lessthan45deg = miterlimit(1/math.sin(math.pi*45/360))
113 miterlimit.lessthan11deg = miterlimit(10) # the default, approximately 11.4783 degress
114 miterlimit.clear = attr.clearclass(miterlimit)
117 _defaultlinewidth = 0.02 * unit.w_cm
118 _defaultlinewidth_pt = unit.topt(_defaultlinewidth)
120 class dash(attr.exclusiveattr, strokestyle):
122 """dash of paths"""
124 def __init__(self, pattern=[], offset=0, rellengths=1):
125 """set pattern with offset.
127 If rellengths is True, interpret all dash lengths relative to current linewidth.
129 attr.exclusiveattr.__init__(self, dash)
130 self.pattern = pattern
131 self.offset = offset
132 self.rellengths = rellengths
134 def processPS(self, file, writer, context, registry):
135 if self.rellengths:
136 patternstring = " ".join(["%f" % (element * context.linewidth_pt/_defaultlinewidth_pt) for element in self.pattern])
137 else:
138 patternstring = " ".join(["%f" % element for element in self.pattern])
139 file.write("[%s] %f setdash\n" % (patternstring, self.offset))
141 def processPDF(self, file, writer, context, registry):
142 if self.rellengths:
143 patternstring = " ".join(["%f" % (element * context.linewidth_pt/_defaultlinewidth_pt) for element in self.pattern])
144 else:
145 patternstring = " ".join(["%f" % element for element in self.pattern])
146 file.write("[%s] %f d\n" % (patternstring, self.offset))
148 def processSVGattrs(self, attrs, writer, context, registry):
149 if self.rellengths:
150 patternstring = " ".join(["%f" % (element * context.linewidth_pt/_defaultlinewidth_pt) for element in self.pattern])
151 else:
152 patternstring = " ".join(["%f" % element for element in self.pattern])
153 if patternstring:
154 attrs["stroke-dasharray"] = patternstring
155 attrs["stroke-dashoffset"] = "%f" % self.offset
156 else:
157 attrs["stroke-dasharray"] = "none"
159 dash.clear = attr.clearclass(dash)
162 class linestyle(attr.exclusiveattr, strokestyle):
164 """linestyle (linecap together with dash) of paths"""
166 def __init__(self, c=linecap.butt, d=dash([])):
167 # XXX better, but at the moment not supported by attr.exlusiveattr would be:
168 # XXX attr.exclusiveattr.__init__(self, [linestyle, linecap, dash])
169 attr.exclusiveattr.__init__(self, linestyle)
170 self.c = c
171 self.d = d
173 def processPS(self, file, writer, context, registry):
174 self.c.processPS(file, writer, context, registry)
175 self.d.processPS(file, writer, context, registry)
177 def processPDF(self, file, writer, context, registry):
178 self.c.processPDF(file, writer, context, registry)
179 self.d.processPDF(file, writer, context, registry)
181 def processSVGattrs(self, attrs, writer, context, registry):
182 self.c.processSVGattrs(attrs, writer, context, registry)
183 self.d.processSVGattrs(attrs, writer, context, registry)
185 linestyle.solid = linestyle(linecap.butt, dash([]))
186 linestyle.dashed = linestyle(linecap.butt, dash([2]))
187 linestyle.dotted = linestyle(linecap.round, dash([0, 2]))
188 linestyle.dashdotted = linestyle(linecap.round, dash([0, 2, 2, 2]))
189 linestyle.clear = attr.clearclass(linestyle)
192 class linewidth(attr.sortbeforeexclusiveattr, strokestyle):
194 """linewidth of paths"""
196 def __init__(self, width):
197 attr.sortbeforeexclusiveattr.__init__(self, linewidth, [dash, linestyle])
198 self.width = width
200 def processPS(self, file, writer, context, registry):
201 context.linewidth_pt = unit.topt(self.width)
202 file.write("%f setlinewidth\n" % context.linewidth_pt)
204 def processPDF(self, file, writer, context, registry):
205 context.linewidth_pt = unit.topt(self.width)
206 file.write("%f w\n" % context.linewidth_pt)
208 def processSVGattrs(self, attrs, writer, context, registry):
209 context.linewidth_pt = unit.topt(self.width)
210 attrs["stroke-width"] = "%f" % context.linewidth_pt
212 linewidth.THIN = linewidth(_defaultlinewidth/math.sqrt(32))
213 linewidth.THIn = linewidth(_defaultlinewidth/math.sqrt(16))
214 linewidth.THin = linewidth(_defaultlinewidth/math.sqrt(8))
215 linewidth.Thin = linewidth(_defaultlinewidth/math.sqrt(4))
216 linewidth.thin = linewidth(_defaultlinewidth/math.sqrt(2))
217 linewidth.normal = linewidth(_defaultlinewidth)
218 linewidth.thick = linewidth(_defaultlinewidth*math.sqrt(2))
219 linewidth.Thick = linewidth(_defaultlinewidth*math.sqrt(4))
220 linewidth.THick = linewidth(_defaultlinewidth*math.sqrt(8))
221 linewidth.THIck = linewidth(_defaultlinewidth*math.sqrt(16))
222 linewidth.THICk = linewidth(_defaultlinewidth*math.sqrt(32))
223 linewidth.THICK = linewidth(_defaultlinewidth*math.sqrt(64))
224 linewidth.clear = attr.clearclass(linewidth)
227 class fillrule(attr.exclusiveattr, fillstyle):
229 """defines the fill rule to be used"""
231 def __init__(self, even_odd):
232 attr.exclusiveattr.__init__(self, fillrule)
233 self.even_odd = even_odd
235 def processPS(self, file, writer, context, registry):
236 context.fillrule = self.even_odd
238 def processPDF(self, file, writer, context, registry):
239 context.fillrule = self.even_odd
241 def processSVGattrs(self, attrs, writer, context, registry):
242 attrs["fill-rule"] = {0: "nonzero", 1: "evenodd"}[self.even_odd]
244 fillrule.nonzero_winding = fillrule(0)
245 fillrule.even_odd = fillrule(1)
246 fillrule.clear = attr.clearclass(fillrule)