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 Guillaume Chazarain <guichaz@yahoo.fr>
22 assert gtk
.pygtk_version
>= (2, 8)
29 from pysize
.ui
.utils
import human_unit
, min_size_to_consider
, sanitize_string
34 class PysizeWidget_Draw(object):
35 def __init__(self
, options
, args
):
36 self
.connect('expose-event', type(self
)._expose
_event
)
37 self
.modify_font(pango
.FontDescription('Monospace 12'))
38 self
.max_text_height
= self
.measure_font_height()
39 self
.fast
= options
.fast
41 def measure_font_height(self
):
42 w
, h
= self
.create_pango_layout('a').get_pixel_size()
45 def _get_requested_height(self
):
46 return self
.max_text_height
* self
.tree
.root
.size
/ \
47 min_size_to_consider(self
.options
.min_size
)
49 def queue_node_redraw(self
, node
):
51 x0
, x1
, y0
, y1
= map(int, node
.rectangle
)
52 self
.queue_draw_area(x0
, y0
, x1
- x0
, y1
- y0
)
54 def _draw_text(self
, context
, text
, x0
, x1
, y0
, y1
):
55 pl
= self
.create_pango_layout(text
)
56 pl
.set_alignment(pango
.ALIGN_CENTER
)
59 pl
.set_width(int(w
*pango
.SCALE
))
60 pl
.set_ellipsize(pango
.ELLIPSIZE_MIDDLE
)
61 real_w
, real_h
= pl
.get_pixel_size()
62 if real_h
> self
.max_text_height
:
63 self
.max_text_height
= real_h
66 context
.move_to(x0
, y0
+(h
-real_h
)/2.0)
67 context
.set_source_rgb(0, 0, 0)
68 context
.show_layout(pl
)
71 def _get_node_colors(self
, node
, colors
):
72 def transform(colors
, dr
, dg
, db
):
73 return map(lambda (r
, g
, b
): (r
+ dr
, g
+ dg
, b
+ db
), colors
)
75 if node
.is_real() and not node
.is_dir():
76 colors
= transform(colors
, 0.6, -0.6, -0.6)
78 if not node
.is_real():
79 colors
= transform(colors
, 0, 0.4, 0)
81 size
= node
.get_useful_size() / (self
.tree
.root
.children
[0].size
* 2.0)
82 colors
= transform(colors
, -size
, -size
, -size
)
84 if node
== self
.cursor_node
:
85 colors
= transform(colors
, 0.1, 0.1, 0.1)
86 if node
in self
.selected_nodes
+ [self
.button_press_node
]:
87 colors
= transform(colors
, -0.2, -0.2, -0.2)
90 def _draw_box(self
, context
, x0
, x1
, y0
, y1
, node
):
101 node
.rectangle
= x0
, x1
, y0
, y1
104 context
.rectangle(x0
, y0
, x1
- x0
, y1
- y0
)
105 context
.set_source_rgb(0, 0, 0)
106 context
.stroke_preserve()
108 colors
= self
._get
_node
_colors
(node
, ((0.2, 0.4, 1.0),))
109 context
.set_source_rgb(*colors
[0])
113 context
.arc(x0
+ RADIUS
, y0
+ RADIUS
, RADIUS
,
114 - math
.pi
, - math
.pi
/ 2.0)
115 context
.rel_line_to(x1
- x0
- 2*RADIUS
, 0)
116 context
.arc(x1
- RADIUS
, y0
+ RADIUS
, RADIUS
,
118 context
.rel_line_to(0, y1
- y0
- 2*RADIUS
)
119 context
.arc(x1
- RADIUS
, y1
- RADIUS
, RADIUS
,
121 context
.rel_line_to(- x1
+ x0
+ 2*RADIUS
, 0)
122 context
.arc(x0
+ RADIUS
, y1
- RADIUS
, RADIUS
,
123 math
.pi
/ 2.0, math
.pi
)
126 context
.set_source_rgb(0, 0, 0)
127 context
.stroke_preserve()
129 gradient
= cairo
.LinearGradient(0, y0
, 0, y1
)
130 colors
= self
._get
_node
_colors
(node
, ((0.5, 0.4, 1.0),
132 gradient
.add_color_stop_rgb(0.0, *colors
[0])
133 gradient
.add_color_stop_rgb(1.0, *colors
[1])
134 context
.set_source(gradient
)
137 name
= sanitize_string(node
.get_name())
138 size
= human_unit(node
.size
)
139 self
._draw
_text
(context
, name
+ '\n' + size
, x0
, x1
, y0
, y1
) or \
140 self
._draw
_text
(context
, name
, x0
, x1
, y0
, y1
) or \
141 self
._draw
_text
(context
, size
, x0
, x1
, y0
, y1
)
143 def _draw_boxes(self
, context
, node
, depth
, offset
):
144 w
= self
.allocation
.width
145 h
= self
.allocation
.height
146 x0
= depth
* (w
- 1.0) / self
.tree
.height
147 x1
= (depth
+ 1.0) * (w
- 1.0) / self
.tree
.height
148 y0
= (h
- 1.0) * offset
/ self
.tree
.root
.size
149 y1
= (h
- 1.0) * (offset
+ node
.size
) / self
.tree
.root
.size
151 self
._draw
_box
(context
, x0
, x1
, y0
, y1
, node
)
153 for child
in node
.children
:
154 self
._draw
_boxes
(context
, child
, depth
, offset
)
157 def _draw(self
, context
):
158 max_text_height_before
= self
.max_text_height
159 context
.set_line_width(LINE_WIDTH
)
161 for child
in self
.tree
.root
.children
:
162 self
._draw
_boxes
(context
, child
, 0, offset
)
164 if self
.max_text_height
!= max_text_height_before
:
165 self
.schedule_new_tree()
167 def _expose_event(self
, event
):
168 context
= self
.window
.cairo_create()
170 # set a clip region for the expose event
171 context
.rectangle(event
.area
.x
, event
.area
.y
,
172 event
.area
.width
, event
.area
.height
)
178 def max_number_of_nodes(self
):
179 return max(2, self
.allocation
.height
/ self
.max_text_height
)
181 def _get_actual_min_size(self
):
182 min_size
= self
.options
.min_size
183 if min_size
== 'auto':
184 min_size
= self
.tree
.root
.size
* self
.min_size_requested()
187 def _zoom(self
, func
):
188 min_size
= self
._get
_actual
_min
_size
()
189 self
.options
.min_size
= func(min_size
)
190 self
.schedule_new_tree()
193 self
._zoom
(lambda min_size
: 'auto')
196 self
._zoom
(lambda min_size
: str(int(min_size
/ 1.5)))
199 self
._zoom
(lambda min_size
: str(int(min_size
* 1.5)))