use pfm as a fallback of afm font metrices to avoid guessing of font parameters whene...
[PyX/mjg.git] / pyx / style.py
blob39883c82d63e29328d1232d7a64f6797eb5d0374
1 # -*- encoding: utf-8 -*-
4 # Copyright (C) 2002-2011 Jörg Lehmann <joergl@users.sourceforge.net>
5 # Copyright (C) 2003-2006 Michael Schindler <m-schindler@users.sourceforge.net>
6 # Copyright (C) 2002-2011 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 import attr, unit, canvasitem
26 import bbox as bboxmodule
29 # base classes for stroke and fill styles
32 class strokestyle(canvasitem.canvasitem):
33 def bbox(self):
34 # TODO: see TODO in bbox method of canvasitem
35 return bboxmodule.empty()
37 class fillstyle(canvasitem.canvasitem):
38 def bbox(self):
39 # TODO: see TODO in bbox method of canvasitem
40 return bboxmodule.empty()
43 # common stroke styles
47 class linecap(attr.exclusiveattr, strokestyle):
49 """linecap of paths"""
51 def __init__(self, value=0):
52 attr.exclusiveattr.__init__(self, linecap)
53 self.value = value
55 def processPS(self, file, writer, context, registry, bbox):
56 file.write("%d setlinecap\n" % self.value)
58 def processPDF(self, file, writer, context, registry, bbox):
59 file.write("%d J\n" % self.value)
61 linecap.butt = linecap(0)
62 linecap.round = linecap(1)
63 linecap.square = linecap(2)
64 linecap.clear = attr.clearclass(linecap)
67 class linejoin(attr.exclusiveattr, strokestyle):
69 """linejoin of paths"""
71 def __init__(self, value=0):
72 attr.exclusiveattr.__init__(self, linejoin)
73 self.value = value
75 def processPS(self, file, writer, context, registry, bbox):
76 file.write("%d setlinejoin\n" % self.value)
78 def processPDF(self, file, writer, context, registry, bbox):
79 file.write("%d j\n" % self.value)
81 linejoin.miter = linejoin(0)
82 linejoin.round = linejoin(1)
83 linejoin.bevel = linejoin(2)
84 linejoin.clear = attr.clearclass(linejoin)
87 class miterlimit(attr.exclusiveattr, strokestyle):
89 """miterlimit of paths"""
91 def __init__(self, value=10.0):
92 attr.exclusiveattr.__init__(self, miterlimit)
93 self.value = value
95 def processPS(self, file, writer, context, registry, bbox):
96 file.write("%f setmiterlimit\n" % self.value)
98 def processPDF(self, file, writer, context, registry, bbox):
99 file.write("%f M\n" % self.value)
101 miterlimit.lessthan180deg = miterlimit(1/math.sin(math.pi*180/360))
102 miterlimit.lessthan90deg = miterlimit(1/math.sin(math.pi*90/360))
103 miterlimit.lessthan60deg = miterlimit(1/math.sin(math.pi*60/360))
104 miterlimit.lessthan45deg = miterlimit(1/math.sin(math.pi*45/360))
105 miterlimit.lessthan11deg = miterlimit(10) # the default, approximately 11.4783 degress
106 miterlimit.clear = attr.clearclass(miterlimit)
109 _defaultlinewidth = 0.02 * unit.w_cm
110 _defaultlinewidth_pt = unit.topt(_defaultlinewidth)
112 class dash(attr.exclusiveattr, strokestyle):
114 """dash of paths"""
116 def __init__(self, pattern=[], offset=0, rellengths=1):
117 """set pattern with offset.
119 If rellengths is True, interpret all dash lengths relative to current linewidth.
121 attr.exclusiveattr.__init__(self, dash)
122 self.pattern = pattern
123 self.offset = offset
124 self.rellengths = rellengths
126 def processPS(self, file, writer, context, registry, bbox):
127 if self.rellengths:
128 patternstring = " ".join(["%f" % (element * context.linewidth_pt/_defaultlinewidth_pt) for element in self.pattern])
129 else:
130 patternstring = " ".join(["%f" % element for element in self.pattern])
131 file.write("[%s] %d setdash\n" % (patternstring, self.offset))
133 def processPDF(self, file, writer, context, registry, bbox):
134 if self.rellengths:
135 patternstring = " ".join(["%f" % (element * context.linewidth_pt/_defaultlinewidth_pt) for element in self.pattern])
136 else:
137 patternstring = " ".join(["%f" % element for element in self.pattern])
138 file.write("[%s] %d d\n" % (patternstring, self.offset))
140 dash.clear = attr.clearclass(dash)
143 class linestyle(attr.exclusiveattr, strokestyle):
145 """linestyle (linecap together with dash) of paths"""
147 def __init__(self, c=linecap.butt, d=dash([])):
148 # XXX better, but at the moment not supported by attr.exlusiveattr would be:
149 # XXX attr.exclusiveattr.__init__(self, [linestyle, linecap, dash])
150 attr.exclusiveattr.__init__(self, linestyle)
151 self.c = c
152 self.d = d
154 def processPS(self, file, writer, context, registry, bbox):
155 self.c.processPS(file, writer, context, registry, bbox)
156 self.d.processPS(file, writer, context, registry, bbox)
158 def processPDF(self, file, writer, context, registry, bbox):
159 self.c.processPDF(file, writer, context, registry, bbox)
160 self.d.processPDF(file, writer, context, registry, bbox)
162 linestyle.solid = linestyle(linecap.butt, dash([]))
163 linestyle.dashed = linestyle(linecap.butt, dash([2]))
164 linestyle.dotted = linestyle(linecap.round, dash([0, 2]))
165 linestyle.dashdotted = linestyle(linecap.round, dash([0, 2, 2, 2]))
166 linestyle.clear = attr.clearclass(linestyle)
169 class linewidth(attr.sortbeforeexclusiveattr, strokestyle):
171 """linewidth of paths"""
173 def __init__(self, width):
174 attr.sortbeforeexclusiveattr.__init__(self, linewidth, [dash, linestyle])
175 self.width = width
177 def processPS(self, file, writer, context, registry, bbox):
178 file.write("%f setlinewidth\n" % unit.topt(self.width))
179 context.linewidth_pt = unit.topt(self.width)
181 def processPDF(self, file, writer, context, registry, bbox):
182 file.write("%f w\n" % unit.topt(self.width))
183 context.linewidth_pt = unit.topt(self.width)
185 linewidth.THIN = linewidth(_defaultlinewidth/math.sqrt(32))
186 linewidth.THIn = linewidth(_defaultlinewidth/math.sqrt(16))
187 linewidth.THin = linewidth(_defaultlinewidth/math.sqrt(8))
188 linewidth.Thin = linewidth(_defaultlinewidth/math.sqrt(4))
189 linewidth.thin = linewidth(_defaultlinewidth/math.sqrt(2))
190 linewidth.normal = linewidth(_defaultlinewidth)
191 linewidth.thick = linewidth(_defaultlinewidth*math.sqrt(2))
192 linewidth.Thick = linewidth(_defaultlinewidth*math.sqrt(4))
193 linewidth.THick = linewidth(_defaultlinewidth*math.sqrt(8))
194 linewidth.THIck = linewidth(_defaultlinewidth*math.sqrt(16))
195 linewidth.THICk = linewidth(_defaultlinewidth*math.sqrt(32))
196 linewidth.THICK = linewidth(_defaultlinewidth*math.sqrt(64))
197 linewidth.clear = attr.clearclass(linewidth)
200 class fillrule(attr.exclusiveattr):
202 """defines the fill rule to be used"""
204 def __init__(self, even_odd):
205 attr.exclusiveattr.__init__(self, fillrule)
206 self.even_odd = even_odd
208 def processPS(self, file, writer, context, registry, bbox):
209 pass
211 def processPDF(self, file, writer, context, registry, bbox):
212 pass
214 fillrule.nonzero_winding = fillrule(0)
215 fillrule.even_odd = fillrule(1)
216 fillrule.clear = attr.clearclass(fillrule)