Adding Pychart due to bug in recent pychart versions
[odoo/odoo.git] / bin / pychart / axis.py
1 #
2 # Copyright (C) 2000-2005 by Yasushi Saito (yasushi.saito@gmail.com)
3
4 # Jockey is free software; you can redistribute it and/or modify it
5 # under the terms of the GNU General Public License as published by the
6 # Free Software Foundation; either version 2, or (at your option) any
7 # later version.
8 #
9 # Jockey is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 # for more details.
13 #
14 import font
15 import pychart_util
16 import chart_object
17 import line_style
18 import math
19 import theme
20 import axis_doc
21 from pychart_types import *
22 from types import *
23
24 class T(chart_object.T):
25     keys = {
26        "tic_interval" : (IntervalType, None, 
27                          pychart_util.interval_desc("tick marks")),
28        "tic_len" : (UnitType, 6, """The length of tick lines. The value can be negative, in which case the tick lines are drawn right of (or above) the axis."""),
29        "minor_tic_interval" : (IntervalType, None,
30                                pychart_util.interval_desc("minor tick marks")),
31        "minor_tic_len" : (UnitType, 3, """The length of minor tick marks.  The value can be negative, in which case the tick lines are drawn right of (or above) the axis."""),
32        "line_style": (line_style.T, line_style.default, 
33                       "Specifies the style of axis and tick lines."),
34        "label": (types.StringType, "axis label",
35                  "The descriptive string displayed below (or to the left of) the axis. <<font>>."),
36        "format": (FormatType, "%s", 
37                   """The format string for tick labels.
38                   It can be a `printf' style format string, or 
39                   a single-parameter function that takes an X (or Y) value
40                   and returns a string. """ +
41                   pychart_util.string_desc),
42        "label_offset": (CoordOrNoneType, (None,None),
43                         """The location for drawing the axis label, 
44                         relative to the middle point of the axis.
45                         If the value is None, the label is displayed
46                         below (or to the left of) of axis at the middle."""),
47        "tic_label_offset": (CoordType, (0,0),
48                             """The location for drawing tick labels, 
49                             relative to the tip of the tick line."""),
50        "offset": (UnitType, 0,
51                   """The location of the axis. 
52                   The value of 0 draws the
53                   axis at the left (for the Y axis) or bottom (for the X axis)
54                   edge of the drawing area.
55                   """)
56        }
57
58 class X(T):
59     keys = pychart_util.union_dict(T.keys,
60                                    {"draw_tics_above": (IntType, 0,
61                                                         "If true, tick lines and labels are drawn above the axis line.")})
62     __doc__ = axis_doc.doc_x
63 ##AUTOMATICALLY GENERATED
64
65 ##END AUTOMATICALLY GENERATED
66     def draw_below(self, ar, can):
67         self.type_check()
68         self.tic_interval = self.tic_interval or ar.x_grid_interval
69         y_base = ar.loc[1] + self.offset
70       
71         can.line(self.line_style, ar.loc[0], y_base,
72                     ar.loc[0]+ ar.size[0], y_base)
73
74         tic_dic = {}
75         max_tic_height = 0
76       
77         for i in ar.x_tic_points(self.tic_interval):
78             tic_dic[i] = 1
79             ticx = ar.x_pos(i)
80
81             str = "/hC" + pychart_util.apply_format(self.format, (i, ), 0)
82
83             (total_height, base_height) = font.text_height(str)
84             max_tic_height = max(max_tic_height, total_height)
85
86             can.line(self.line_style, ticx, y_base, ticx, y_base-self.tic_len)
87             can.show(ticx+self.tic_label_offset[0], 
88                         y_base-self.tic_len-base_height+self.tic_label_offset[1],
89                         str)
90          
91         if self.minor_tic_interval:
92             for i in ar.x_tic_points(self.minor_tic_interval):
93                 if tic_dic.has_key(i):
94                     # a major tic was drawn already.
95                     pass
96                 else:
97                     ticx = ar.x_pos(i)
98                     can.line(self.line_style, ticx, y_base, ticx,
99                                 y_base-self.minor_tic_len)
100
101         self.draw_label(ar, can, y_base - self.tic_len - max_tic_height - 10)
102         
103     def draw_above(self, ar, can):
104         y_base = ar.loc[1] + self.offset
105       
106         tic_dic = {}
107         max_tic_height = 0
108       
109         for i in ar.x_tic_points(self.tic_interval):
110             tic_dic[i] = 1
111             ticx = ar.x_pos(i)
112
113             str = "/hC" + pychart_util.apply_format(self.format, (i, ), 0)
114
115             (total_height, base_height) = font.text_height(str)
116             max_tic_height = max(max_tic_height, total_height)
117
118             can.line(self.line_style, ticx, y_base, ticx, y_base + self.tic_len)
119             can.show(ticx+self.tic_label_offset[0], 
120                      y_base + self.tic_len + base_height + self.tic_label_offset[1],
121                      str)
122          
123         if self.minor_tic_interval:
124             for i in ar.x_tic_points(self.minor_tic_interval):
125                 if tic_dic.has_key(i):
126                     # a major tic was drawn already.
127                     pass
128                 else:
129                     ticx = ar.x_pos(i)
130                     can.line(self.line_style, ticx, y_base, ticx,
131                              y_base + self.minor_tic_len)
132         self.draw_label(ar, can, y_base + self.tic_len + max_tic_height + 10)
133         
134     def draw_label(self, ar, can, ylabel):
135         if self.label == None: return
136     
137         str = "/hC/vM" + self.label
138         (label_height, base_height) = font.text_height(str)
139         xlabel = ar.loc[0] + ar.size[0]/2.0
140         if self.label_offset[0] != None:
141             xlabel += self.label_offset[0]
142         if self.label_offset[1] != None:
143             ylabel += self.label_offset[1]
144         can.show(xlabel, ylabel, str)
145         
146     def draw(self, ar, can):
147         self.type_check()
148         self.tic_interval = self.tic_interval or ar.x_grid_interval
149         y_base = ar.loc[1] + self.offset
150         can.line(self.line_style, ar.loc[0], y_base,
151                  ar.loc[0]+ ar.size[0], y_base)
152         if self.draw_tics_above:
153             self.draw_above(ar, can)
154         else:
155             self.draw_below(ar, can)
156 class Y(T):
157     __doc__ = axis_doc.doc_y   
158     keys = pychart_util.union_dict(T.keys,
159                                    {"draw_tics_right": (IntType, 0,
160                                                         "If true, tick lines and labels are drawn right of the axis line.")})
161     
162     def draw_left(self, ar, can):
163         x_base = ar.loc[0] + self.offset
164         xmin = 999999
165         tic_dic = {}
166         for i in ar.y_tic_points(self.tic_interval):
167             y_tic = ar.y_pos(i)
168             tic_dic[i] = 1
169             can.line(self.line_style, x_base, y_tic,
170                      x_base - self.tic_len, y_tic)
171             str = pychart_util.apply_format(self.format, (i,), 0)
172             if self.tic_len > 0: str = "/hR" + str
173
174             tic_height, base_height = font.text_height(str)
175             x = x_base - self.tic_len + self.tic_label_offset[0]
176             can.show(x, y_tic - tic_height/2.0 + self.tic_label_offset[1],
177                      str)
178             xmin = min(xmin, x - font.text_width(str))
179             
180         if self.minor_tic_interval:
181             for i in ar.y_tic_points(self.minor_tic_interval):
182                 if tic_dic.has_key(i):
183                     # a major tic line was drawn already.
184                     pass
185                 else:
186                     y_tic = ar.y_pos(i)
187                     can.line(self.line_style, x_base, y_tic,
188                              x_base - self.minor_tic_len, y_tic)
189                
190         self.draw_label(ar, can, xmin - theme.default_font_size/2.0)
191
192     def draw_right(self, ar, can):
193         x_base = ar.loc[0] + self.offset
194         xmax = 0
195         tic_dic = {}
196         for i in ar.y_tic_points(self.tic_interval):
197             y_tic = ar.y_pos(i)
198             tic_dic[i] = 1
199             can.line(self.line_style, x_base, y_tic,
200                      x_base + self.tic_len, y_tic)
201             str = pychart_util.apply_format(self.format, (i,), 0)
202             if self.tic_len > 0: str = "/hL" + str
203
204             tic_height, base_height = font.text_height(str)
205             x = x_base + self.tic_len + self.tic_label_offset[0]
206             can.show(x, y_tic - tic_height/2.0 + self.tic_label_offset[1],
207                      str)
208             xmax = max(xmax, x + font.text_width(str))
209             
210         if self.minor_tic_interval:
211             for i in ar.y_tic_points(self.minor_tic_interval):
212                 if tic_dic.has_key(i):
213                     # a major tic line was drawn already.
214                     pass
215                 else:
216                     y_tic = ar.y_pos(i)
217                     can.line(self.line_style, x_base, y_tic,
218                              x_base + self.minor_tic_len, y_tic)
219
220         self.draw_label(ar, can, xmax + theme.default_font_size)
221         
222     def draw_label(self, ar, can, xlabel):
223         if self.label == None:
224             return
225         ylabel = ar.loc[1] + ar.size[1] / 2
226         if self.label_offset[0] != None:
227             xlabel += self.label_offset[0]
228         if self.label_offset[1] != None:
229             ylabel += self.label_offset[1]
230         can.show(xlabel, ylabel, "/a90/hC" + self.label)
231
232     def draw(self, ar, can):
233         self.type_check()
234         self.tic_interval = self.tic_interval or ar.y_grid_interval
235         
236         x_base = ar.loc[0] + self.offset
237         can.line(self.line_style, x_base, ar.loc[1], x_base, ar.loc[1]+ar.size[1])
238         if self.draw_tics_right:
239             self.draw_right(ar, can)
240         else:
241             self.draw_left(ar, can)