Clean user given filenames, and set the same behaviour in curses as in gtk:
[pysize.git] / ui / char_matrix.py
blobaca49364e088f710ae6a8c45b60740c6b023320d
1 import math
2 from ui.utils import human_unit, short_string
4 # A character is composed of 9 positions
5 # 012
6 # 345
7 # 678
9 # 9: selection bit
11 # Example :
12 # '+' = 1, 3, 4, 5, 7 = (1<<1) + (1<<3) + (1<<4) + (1<<5) + (1<<7) = 186
14 HLINE_START = (1<<4) + (1<<5)
15 HLINE_END = (1<<3) + (1<<4)
16 HLINE = HLINE_START | HLINE_END
18 VLINE_START = (1<<4) + (1<<7)
19 VLINE_END = (1<<1) + (1<<4)
20 VLINE = VLINE_START | VLINE_END
22 MASK = (1<<9) - 1
23 SELECTED = 1<<9
25 class CharMatrix:
26 """A 2D array of characters."""
27 def __init__(self, width, height, tree, selected_node=None):
28 self.width = width
29 self.height = height
30 self.tree = tree
31 self.selected_node = selected_node
32 self.matrix = [[0 for i in xrange(width)] for j in xrange(height)]
33 self._horizontal_line(0, 0, width)
34 self._horizontal_line(0, height - 1, width)
35 self._vertical_line(0, 0, height)
36 self._vertical_line(width - 1, 0, height)
38 if not tree.root:
39 return
41 offset = 0
42 total_size = tree.root.size
43 for child in tree.root.get_children():
44 offset += self._draw_boxes(child, 0, offset,
45 self.height - 1 - offset, total_size)
46 total_size -= child.size
48 def _compose_point(self, x, y, new):
49 self.matrix[y][x] |= new
51 def _horizontal_line(self, x, y, length, mask=0):
52 self._compose_point(x, y, HLINE_START | mask)
53 for i in xrange(x + 1, x + length - 1):
54 self._compose_point(i, y, HLINE | mask)
55 self._compose_point(x + length - 1, y, HLINE_END | mask)
57 def _vertical_line(self, x, y, length, mask=0):
58 self._compose_point(x, y, VLINE_START | mask)
59 for i in xrange(y + 1, y + length - 1):
60 self._compose_point(x, i, VLINE | mask)
61 self._compose_point(x, y + length - 1, VLINE_END | mask)
63 def _draw_string(self, x, y, length, string):
64 try:
65 decoded = string.decode('UTF-8')
66 except UnicodeDecodeError:
67 decoded = string
68 print_string = short_string(decoded, length)
69 self.matrix[y][x:x+len(print_string)] = print_string
71 def _draw_box(self, x0, x1, y0, y1, node, mask):
72 node.rectangle = (x0, x1, y0, y1)
73 length = x1 - x0
74 if y1 > y0:
75 self._horizontal_line(x0, y0, length + 1, mask)
76 self._horizontal_line(x0, y1, length + 1, mask)
77 self._vertical_line(x0, y0, y1 - y0 + 1, mask)
78 self._vertical_line(x1, y0, y1 - y0 + 1, mask)
80 if node.is_real():
81 if y1 > y0 + 1:
82 self._draw_string(x0+1, (y0+y1)/2, length - 2,
83 node.get_name())
84 if y1 > y0 + 2:
85 self._draw_string(x0+1, (y0+y1)/2 + 1, length - 2,
86 human_unit(node.size))
87 else:
88 # For the 'remaining' node, the size is more important than
89 # the dumy name, so we print it instead of the name when there is
90 # room for a single line
91 size_string_y = (y0+y1)/2 + 1
92 if y1 > y0 + 2:
93 self._draw_string(x0+1, (y0+y1)/2, length - 2,
94 node.get_name())
95 else:
96 size_string_y -= 1
97 if y1 > y0 + 1:
98 self._draw_string(x0 + 1, size_string_y, length - 2,
99 human_unit(node.size))
101 def _draw_boxes(self, node, depth, offset, length, total_size):
102 x0 = depth * (self.width - 1) / self.tree.height
103 x1 = (depth + 1) * (self.width - 1) / self.tree.height
104 y0 = offset
105 y1 = offset + min(length, int(math.ceil(float(node.size) * length /
106 total_size)))
108 if node == self.selected_node:
109 mask = SELECTED
110 else:
111 mask = 0
113 self._draw_box(x0, x1, y0, y1, node, mask)
114 depth += 1
115 child_offset = 0
116 total_size = node.size
117 for child in node.get_children():
118 child_offset += self._draw_boxes(child, depth,
119 offset + child_offset,
120 y1 - y0 - child_offset,
121 total_size)
122 total_size -= child.size
123 return y1 - y0