[MERGE] Remove the embedded pychart library, and use the online version
[odoo/odoo.git] /
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2000-2005 by Yasushi Saito (yasushi.saito@gmail.com)
4
5 # Jockey is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2, or (at your option) any
8 # later version.
9 #
10 # Jockey is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 # for more details.
14 #
15 import line_style
16 import color
17 import chart_object
18 import object_set
19 import math
20 import arrow_doc
21 import canvas
22
23 from pychart_types import *
24 from types import *
25 from scaling import *
26
27 __doc__ = """
28 Arrow is an optional component of a chart that draws line segments with
29 an arrowhead. To draw an arrow, one creates an arrow.T object, and calls
30 its "draw" method usually after area.draw() is called (otherwise, area.draw()
31 may overwrite the arrow). For example, the below code draws an arrow
32 from (10,10) to (20,30).
33
34 ar = area.T(...)
35 a = arrow.T(head_style = 1)
36 ar.draw()
37 a.draw([(10,10), (20,30)])
38 """
39
40 def draw_arrowhead(can, tailx, taily, tipx, tipy, thickness, head_len, style):
41     can.comment("ARROWHEAD tail=(%d,%d) tip=(%d,%d)\n" 
42                 % (tailx, taily, tipx, tipy))
43     
44     halfthickness = thickness/2.0
45     dx = tipx - tailx
46     dy = tipy - taily
47     arrow_len = math.sqrt(dx*dx + dy*dy)
48     angle = math.atan2(dy, dx) * 360 / (2*math.pi)
49     base = arrow_len - head_len
50     can.push_transformation((tailx, taily), None, angle)    
51
52     can.newpath()
53     if style == 0:
54         can.moveto(base, - halfthickness)
55         can.lineto(base, halfthickness)
56         can.lineto(arrow_len, 0)
57         can.closepath()
58     elif style == 1:
59         depth = head_len / 2.5
60         can.moveto(base - depth, -halfthickness)
61         can.lineto(base, 0)
62         can.lineto(base - depth, halfthickness)
63         can.lineto(arrow_len, 0)
64         can.closepath()
65     elif style == 2:
66         can.moveto(base + head_len/2.0, 0)
67         can.path_arc(base + head_len / 2.0, 0, head_len / 2.0, 1.0, 0, 400)
68     elif style == 3:
69         can.moveto(base, 0)
70         can.lineto(base + head_len/2.0, -halfthickness)
71         can.lineto(arrow_len, 0)
72         can.lineto(base + head_len/2.0, halfthickness)
73         can.closepath()
74     else:
75         raise Exception, "Arrow style must be a number between 0 and 3."
76     can.fill()
77     can.pop_transformation()
78     can.comment("end ARROWHEAD.\n")
79
80 def draw_arrowbody(can, tailx, taily, tipx, tipy, head_len):
81     dx = tipx - tailx
82     dy = tipy - taily
83     arrow_len = math.sqrt(dx*dx + dy*dy)
84     angle = math.atan2(dy, dx) * 360 / (2*math.pi)
85     base = arrow_len - head_len
86     can.push_transformation((tailx, taily), None, angle)
87     can.moveto(0, 0)
88     can.lineto(base+head_len*0.1, 0)
89     can.stroke()
90     can.pop_transformation()
91
92
93 class T(chart_object.T):
94     __doc__ = arrow_doc.doc
95     keys = {
96         "thickness" : (UnitType, 4,
97                         "The width of the arrow head."),
98         "head_len": (UnitType, 8,
99                     "The length of the arrow head."),
100         "head_color": (color.T, color.default,
101                       "The color of the arrow head."),
102         "line_style": (line_style.T, line_style.default,
103                        "Line style."),
104         "head_style": (IntType, 1,
105                        "The value of 0 draws a triangular arrow head. The value of 1 draws a swallow-tail arrow head. The value of 2 draws a circular head. The value of 3 draws a diamond-shaped head.")
106             }
107 ##AUTOMATICALLY GENERATED
108
109 ##END AUTOMATICALLY GENERATED
110     def draw(self, points, can = None):
111         """Parameter <points> specifies the
112         list of points the arrow traverses through.
113         It should contain at least two points, i.e.,
114         the tail and tip. Parameter
115         <can> is an optional parameter that specifies the output.
116         <<canvas>>
117         """
118         if can == None: can = canvas.default_canvas()
119         self.type_check()
120         xtip = points[-1][0]
121         ytip = points[-1][1]
122         
123         xtail = points[-2][0]
124         ytail = points[-2][1]
125
126         can.newpath()
127         can.set_line_style(self.line_style)
128         if len(points) > 2:
129             can.moveto(points[0][0], points[0][1])
130             for i in range(1, len(points)-1):
131                 can.lineto(points[i][0], points[i][1])
132
133         draw_arrowbody(can, xscale(xtail), yscale(ytail),
134                        yscale(xtip), yscale(ytip),
135                        nscale(self.head_len))
136
137         can.set_fill_color(self.head_color)
138         draw_arrowhead(can, xscale(xtail), yscale(ytail),
139                        xscale(xtip), yscale(ytip),
140                        nscale(self.thickness),
141                        nscale(self.head_len),
142                        self.head_style)
143         
144         can.setbb(xtail, ytail)
145         can.setbb(xtip, ytip)
146
147 standards = object_set.T()
148 def _intern(a):
149     global standards
150     standards.add(a)
151     return a
152
153 a0 = _intern(T(head_style=0))
154 a1 = _intern(T(head_style=1))
155 a2 = _intern(T(head_style=2))
156 a3 = _intern(T(head_style=3))
157 gray0 = _intern(T(head_style=0, head_color = color.gray50,
158                   line_style=line_style.T(color=color.gray50)))
159 gray1 = _intern(T(head_style=1, head_color = color.gray50,
160                   line_style=line_style.T(color=color.gray50)))
161 gray2 = _intern(T(head_style=2, head_color = color.gray50,
162                   line_style=line_style.T(color=color.gray50)))
163 gray3 = _intern(T(head_style=3, head_color = color.gray50,
164                   line_style=line_style.T(color=color.gray50)))
165
166 fat0 = _intern(T(head_style=0, head_len=12, thickness=10, line_style=line_style.T(width=2)))
167 fat1 = _intern(T(head_style=1, head_len=12, thickness=10, line_style=line_style.T(width=2)))
168 fat2 = _intern(T(head_style=2, head_len=12, thickness=10, line_style=line_style.T(width=2)))
169 fat3 = _intern(T(head_style=3, head_len=12, thickness=10, line_style=line_style.T(width=2)))
170 fatgray0 = _intern(T(head_style=0, head_len=12, thickness=10,
171                       head_color = color.gray50,
172                       line_style=line_style.T(width=2, color=color.gray50)))
173 fatgray1 = _intern(T(head_style=1, head_len=12, thickness=10,
174                       head_color = color.gray50,
175                       line_style=line_style.T(width=2, color=color.gray50)))
176 fatgray2 = _intern(T(head_style=2, head_len=12, thickness=10,
177                       head_color = color.gray50,
178                       line_style=line_style.T(width=2, color=color.gray50)))
179 fatgray3 = _intern(T(head_style=3, head_len=12, thickness=10,
180                       head_color = color.gray50,
181                       line_style=line_style.T(width=2, color=color.gray50)))
182
183 default = a1
184
185