7 assert gtk
.pygtk_version
>= (2, 8)
9 from core
.pysize_fs_tree
import pysize_tree
10 from ui
.utils
import human_unit
16 class PysizeWidget(gtk
.DrawingArea
):
17 def __init__(self
, options
, args
):
18 super(PysizeWidget
, self
).__init
__()
19 self
.connect('expose-event', self
._expose
)
20 self
.connect('realize', self
._realize
)
21 self
.connect('motion-notify-event', self
._motion
)
22 self
.connect('configure-event', self
._configure
)
23 self
.connect('key-press-event', self
._key
_press
)
24 self
.connect('button-press-event', self
._button
_press
)
25 self
.connect('button-release-event', self
._button
_release
)
26 self
.set_flags(gtk
.CAN_FOCUS
)
27 self
.modify_font(pango
.FontDescription('Monospace 12'))
28 self
.options
= options
30 self
.needs_tree
= True
31 self
.tree
= pysize_tree(args
[0], options
.max_depth
, 1.0)
32 self
.selected_nodes
= []
33 self
.cursor_node
= None
34 self
.button_press_node
= None
36 def _get_node_here(self
, event
):
37 for node
in self
.tree
.root
:
38 if node
.contains_point(event
):
41 def _queue_node_redraw(self
, node
):
43 (x0
, x1
, y0
, y1
) = map(int, node
.rectangle
)
44 self
.queue_draw_area(x0
, y0
, x1
- x0
, y1
- y0
)
46 def _button_press(self
, widget
, event
):
47 node
= self
._get
_node
_here
(event
)
48 if node
!= self
.button_press_node
:
49 self
._queue
_node
_redraw
(self
.button_press_node
)
50 self
._queue
_node
_redraw
(node
)
51 self
.button_press_node
= node
53 def _button_release(self
, widget
, event
):
54 node
= self
._get
_node
_here
(event
)
55 self
._queue
_node
_redraw
(self
.button_press_node
)
56 self
._queue
_node
_redraw
(node
)
57 same_as_press
= node
== self
.button_press_node
58 self
.button_press_node
= None
60 for n
in self
.selected_nodes
:
61 self
._queue
_node
_redraw
(n
)
62 self
._queue
_node
_redraw
(node
)
63 if event
.state
& gtk
.gdk
.CONTROL_MASK
:
64 self
.selected_nodes
.append(node
)
66 self
.selected_nodes
= [node
]
68 def _key_press(self
, widget
, event
):
70 gtk
.keysyms
.Left
: self
.tree
.get_parent
,
71 gtk
.keysyms
.Up
: self
.tree
.get_previous_sibling
,
72 gtk
.keysyms
.Right
: self
.tree
.get_first_child
,
73 gtk
.keysyms
.Down
: self
.tree
.get_next_sibling
76 action
= directions
.get(event
.keyval
, None)
77 if action
and not self
.cursor_node
is None:
78 new_selection
= action(self
.cursor_node
)
79 if not new_selection
in (None, self
.tree
.root
):
80 self
._queue
_node
_redraw
(self
.cursor_node
)
81 self
._queue
_node
_redraw
(new_selection
)
82 self
.cursor_node
= new_selection
84 def _realize(self
, widget
):
85 events
= self
.window
.get_events()
86 events |
= gtk
.gdk
.POINTER_MOTION_MASK
87 events |
= gtk
.gdk
.POINTER_MOTION_HINT_MASK
88 events |
= gtk
.gdk
.KEY_PRESS_MASK
89 events |
= gtk
.gdk
.BUTTON_PRESS_MASK
90 events |
= gtk
.gdk
.BUTTON_RELEASE_MASK
91 self
.window
.set_events(events
)
92 self
.window
.get_pointer()
94 def _configure(self
, widget
, event
):
95 self
.needs_tree
= True
97 def _motion(self
, widget
, event
):
98 prev_selection
= new_selection
= self
.cursor_node
99 for node
in self
.tree
.root
:
100 was_selected
= node
== prev_selection
101 if node
.contains_point(event
) != (node
== prev_selection
):
102 if node
== prev_selection
:
106 self
._queue
_node
_redraw
(self
.cursor_node
)
107 self
._queue
_node
_redraw
(new_selection
)
108 self
.cursor_node
= new_selection
109 if prev_selection
== new_selection
:
110 self
.window
.get_pointer()
112 def _expose(self
, widget
, event
):
113 context
= widget
.window
.cairo_create()
115 # set a clip region for the expose event
116 context
.rectangle(event
.area
.x
, event
.area
.y
,
117 event
.area
.width
, event
.area
.height
)
121 self
.window
.get_pointer()
124 def _draw_text(self
, context
, text
, x0
, x1
, y0
, y1
):
125 pl
= self
.create_pango_layout(text
)
128 pl
.set_width(int(w
*pango
.SCALE
))
129 pl
.set_ellipsize(pango
.ELLIPSIZE_MIDDLE
)
130 (real_w
, real_h
) = pl
.get_pixel_size()
131 if real_w
> w
or real_h
> h
:
133 if real_w
+w
/20.0 < w
:
135 context
.move_to(x0
, y0
+(h
-real_h
)/2.0)
136 context
.set_source_rgb(0, 0, 0)
137 context
.show_layout(pl
)
140 def _get_node_colors(self
, node
, colors
):
141 if node
== self
.cursor_node
:
142 colors
= map(lambda c
: c
+0.2, colors
)
143 if node
in self
.selected_nodes
:
145 if node
== self
.button_press_node
:
146 colors
= map(lambda c
: c
+0.2, colors
)
149 def _draw_box(self
, context
, x0
, x1
, y0
, y1
, node
):
154 node
.rectangle
= (x0
, x1
, y0
, y1
)
158 context
.arc(x0
+ RADIUS
, y0
+ RADIUS
, RADIUS
,
159 - math
.pi
, - math
.pi
/ 2.0)
160 context
.rel_line_to(x1
- x0
- 2*RADIUS
, 0)
161 context
.arc(x1
- RADIUS
, y0
+ RADIUS
, RADIUS
,
163 context
.rel_line_to(0, y1
- y0
- 2*RADIUS
)
164 context
.arc(x1
- RADIUS
, y1
- RADIUS
, RADIUS
,
166 context
.rel_line_to(- x1
+ x0
+ 2*RADIUS
, 0)
167 context
.arc(x0
+ RADIUS
, y1
- RADIUS
, RADIUS
,
168 math
.pi
/ 2.0, math
.pi
)
171 context
.set_source_rgb(0, 0, 0)
172 context
.stroke_preserve()
174 gradient
= cairo
.LinearGradient(0, y0
, 0, y1
)
175 colors
= self
._get
_node
_colors
(node
, [0.5, 0.5, 1.0, 0.0, 0.5, 1.0])
176 gradient
.add_color_stop_rgb(0.0, *colors
[:3])
177 gradient
.add_color_stop_rgb(1.0, *colors
[3:])
178 context
.set_source(gradient
)
181 context
.rectangle(x0
, y0
, x1
- x0
, y1
- y0
)
182 context
.set_source_rgb(0, 0, 0)
183 context
.stroke_preserve()
185 colors
= self
._get
_node
_colors
(node
, [0, 0.5, 1.0])
186 context
.set_source_rgb(*colors
)
189 name
= node
.get_name()
190 size
= human_unit(node
.size
)
191 if not self
._draw
_text
(context
, name
+ '\n' + size
, x0
, x1
, y0
, y1
):
192 first
, second
= name
, size
193 if not node
.is_real():
194 first
, second
= second
, first
195 if not self
._draw
_text
(context
, first
, x0
, x1
, y0
, y1
):
196 self
._draw
_text
(context
, second
, x0
, x1
, y0
, y1
)
198 def _draw_boxes(self
, context
, node
, depth
, offset
):
199 w
= self
.allocation
.width
200 h
= self
.allocation
.height
201 x0
= depth
* (w
- 1.0) / self
.tree
.height
202 x1
= (depth
+ 1.0) * (w
- 1.0) / self
.tree
.height
203 y0
= (h
- 1.0) * offset
/ self
.tree
.root
.size
204 y1
= (h
- 1.0) * (offset
+ node
.size
) / self
.tree
.root
.size
206 self
._draw
_box
(context
, x0
, x1
, y0
, y1
, node
)
208 for child
in node
.get_children():
209 self
._draw
_boxes
(context
, child
, depth
, offset
)
212 def _draw(self
, context
):
214 self
.tree
= pysize_tree(self
.args
[0], self
.options
.max_depth
,
215 2*RADIUS
/self
.allocation
.height
)
216 self
.needs_tree
= False
217 if not self
.tree
.root
:
219 context
.set_line_width(LINE_WIDTH
)
221 for child
in self
.tree
.root
.get_children():
222 self
._draw
_boxes
(context
, child
, 0, offset
)