Update copyright years
[pysize.git] / pysize / ui / char_matrix.py
blobac75f951c5ac535cee3f10381a6db59a72281341
1 # This program is free software; you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation; either version 2 of the License, or
4 # (at your option) any later version.
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU Library General Public License for more details.
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 # See the COPYING file for license information.
17 # Copyright (c) 2006, 2007, 2008 Guillaume Chazarain <guichaz@yahoo.fr>
19 import math
20 from pysize.ui.utils import human_unit, sanitize_string
22 # A character is composed of 9 positions
23 # 012
24 # 345
25 # 678
27 # 9: selection bit
29 # Example :
30 # '+' = 1, 3, 4, 5, 7 = (1<<1) + (1<<3) + (1<<4) + (1<<5) + (1<<7) = 186
32 HLINE_START = (1<<4) + (1<<5)
33 HLINE_END = (1<<3) + (1<<4)
34 HLINE = HLINE_START | HLINE_END
36 VLINE_START = (1<<4) + (1<<7)
37 VLINE_END = (1<<1) + (1<<4)
38 VLINE = VLINE_START | VLINE_END
40 MASK = (1<<9) - 1
41 SELECTED = 1<<9
43 class CharMatrix(object):
44 """A 2D array of characters."""
45 def __init__(self, width, height, tree, selected_node=None):
46 self.width = width
47 self.height = height
48 self.tree = tree
49 self.selected_node = selected_node
50 self.matrix = [[0 for i in xrange(width)] for j in xrange(height)]
51 self._horizontal_line(0, 0, width)
52 self._horizontal_line(0, height - 1, width)
53 self._vertical_line(0, 0, height)
54 self._vertical_line(width - 1, 0, height)
56 if not tree.root:
57 return
59 offset = 0
60 total_size = tree.root.size
61 for child in tree.root.children or [tree.root]:
62 if child.size:
63 offset += self._draw_boxes(child, 0, offset,
64 self.height - 1 - offset, total_size)
65 total_size -= child.size
67 def _compose_point(self, x, y, new):
68 self.matrix[y][x] |= new
70 def _horizontal_line(self, x, y, length, mask=0):
71 self._compose_point(x, y, HLINE_START | mask)
72 for i in xrange(x + 1, x + length - 1):
73 self._compose_point(i, y, HLINE | mask)
74 self._compose_point(x + length - 1, y, HLINE_END | mask)
76 def _vertical_line(self, x, y, length, mask=0):
77 self._compose_point(x, y, VLINE_START | mask)
78 for i in xrange(y + 1, y + length - 1):
79 self._compose_point(x, i, VLINE | mask)
80 self._compose_point(x, y + length - 1, VLINE_END | mask)
82 def _draw_string(self, x, y, length, string):
83 print_string = sanitize_string(string, max_length=length)
84 self.matrix[y][x:x+len(print_string)] = print_string
86 def _draw_box(self, x0, x1, y0, y1, node, mask):
87 node.rectangle = x0, x1, y0, y1
88 length = x1 - x0
89 name = node.get_name()
90 name_length = len(name)
91 size = human_unit(node.size)
92 if y1 > y0:
93 self._horizontal_line(x0, y0, length + 1, mask)
94 self._horizontal_line(x0, y1, length + 1, mask)
95 self._vertical_line(x0, y0, y1 - y0 + 1, mask)
96 self._vertical_line(x1, y0, y1 - y0 + 1, mask)
98 if y1 > y0 + 1:
99 self._draw_string(x0 + 1, (y0 + y1) / 2, length - 1, name)
101 if y1 > y0 + 2:
102 self._draw_string(x0 + 1, (y0 + y1) / 2 + 1, length - 1, size)
103 elif name_length + 1 + len(size) < length:
104 self._draw_string(x0 + 2 + name_length, (y0 + y1) / 2, length - 1,
105 size)
107 def _draw_boxes(self, node, depth, offset, length, total_size):
108 x0 = depth * (self.width - 1) / (self.tree.height or 1)
109 x1 = (depth + 1) * (self.width - 1) / (self.tree.height or 1)
110 y0 = offset
111 y1 = offset + min(length, int(math.ceil(float(node.size) * length /
112 total_size)))
114 if node == self.selected_node:
115 mask = SELECTED
116 else:
117 mask = 0
119 self._draw_box(x0, x1, y0, y1, node, mask)
120 depth += 1
121 child_offset = 0
122 total_size = node.size
123 for child in node.children:
124 child_offset += self._draw_boxes(child, depth,
125 offset + child_offset,
126 y1 - y0 - child_offset,
127 total_size)
128 total_size -= child.size
129 return y1 - y0