1 from __future__
import generators
5 from xml
.dom
import Node
7 def calc_node(display
, node
, pos
):
8 if node
.nodeType
== Node
.TEXT_NODE
:
9 text
= node
.nodeValue
.strip()
10 elif node
.nodeType
== Node
.ELEMENT_NODE
:
12 for key
in node
.attributes
:
13 a
= node
.attributes
[key
]
14 text
+= ' %s=%s' % (unicode(a
.name
), unicode(a
.value
))
15 elif node
.nodeType
== Node
.COMMENT_NODE
:
16 text
= node
.nodeValue
.strip()
20 text
= '<noname>' + node
.nodeValue
24 layout
= display
.create_pango_layout(text
)
25 width
, height
= layout
.get_pixel_size()
31 fg
= display
.style
.fg_gc
32 bg
= display
.style
.bg_gc
34 surface
.draw_rectangle(fg
[g
.STATE_NORMAL
], True,
36 surface
.draw_rectangle(display
.style
.white_gc
, True,
37 x
+ 1, y
+ 1, 6, height
- 3)
39 if node
in display
.selection
:
40 surface
.draw_rectangle(bg
[g
.STATE_SELECTED
], True,
41 x
+ 12, y
, width
- 1, height
- 1)
42 surface
.draw_layout(fg
[g
.STATE_SELECTED
], x
+ 12, y
, layout
)
44 if node
.nodeType
== Node
.TEXT_NODE
:
45 gc
= style
.text_gc
[g
.STATE_NORMAL
]
47 gc
= style
.fg_gc
[g
.STATE_NORMAL
]
48 surface
.draw_layout(gc
, x
+ 12, y
, layout
)
50 bbox
= (x
, y
, x
+ 12 + width
, y
+ height
)
53 class Display(g
.EventBox
):
54 def __init__(self
, window
, view
):
55 g
.EventBox
.__init
__(self
)
56 self
.set_app_paintable(True)
57 self
.set_double_buffered(False)
58 self
.update_timeout
= 0
61 self
.parent_window
= window
64 s
= self
.get_style().copy()
65 s
.bg
[g
.STATE_NORMAL
] = g
.gdk
.color_parse('old lace')
66 s
.text
[g
.STATE_NORMAL
] = g
.gdk
.color_parse('blue')
69 #self.connect('destroy', self.destroyed)
70 self
.connect('button-press-event', self
.bg_event
)
71 self
.connect('button-release-event', self
.bg_event
)
75 #rox.app_options.add_notify(self.options_changed)
77 # Display is relative to this node, which is the highest displayed node (possibly
78 # off the top of the screen)
79 self
.ref_node
= view
.root
82 self
.last_alloc
= None
83 self
.connect('size-allocate', lambda w
, a
: self
.size_allocate(a
))
84 self
.connect('size-request', lambda w
, r
: self
.size_request(r
))
85 self
.connect('expose-event', lambda w
, e
: 1)
87 self
.pan_timeout
= None
88 self
.h_limits
= (0, 0)
91 def size_allocate(self
, alloc
):
92 new
= (alloc
.width
, alloc
.height
)
93 if self
.last_alloc
== new
:
97 #print "Alloc", alloc.width, alloc.height
98 pm
= g
.gdk
.Pixmap(self
.window
, alloc
.width
, alloc
.height
, -1)
99 self
.window
.set_back_pixmap(pm
, False)
104 if not self
.pm
: return
107 self
.update_timeout
= 0
109 self
.pm
.draw_rectangle(self
.style
.bg_gc
[g
.STATE_NORMAL
], True,
110 0, 0, self
.last_alloc
[0], self
.last_alloc
[1])
112 self
.drawn
= {} # xmlNode -> (x1, y1, y2, y2)
115 p
= self
.view
.root
.parentNode
120 self
.ref_node
= self
.view
.root
121 self
.ref_pos
= (0, 0)
125 for n
in self
.view
.current_nodes
:
126 self
.selection
[n
] = None
128 pos
= list(self
.ref_pos
)
129 self
.h_limits
= (self
.ref_pos
[0], self
.ref_pos
[0]) # Left, Right
131 for node
, bbox
, draw_fn
in self
.walk_tree(self
.ref_node
, self
.ref_pos
):
132 if bbox
[1] > self
.last_alloc
[1]: break # Off-screen
135 self
.drawn
[node
] = bbox
138 self
.ref_pos
= bbox
[:2]
139 self
.h_limits
= (min(self
.h_limits
[0], bbox
[0]),
140 max(self
.h_limits
[1], bbox
[2]))
146 def walk_tree(self
, node
, pos
):
147 """Yield this (node, bbox), and all following ones in document order."""
150 bbox
, draw_fn
= calc_node(self
, node
, pos
)
151 yield (node
, bbox
, draw_fn
)
154 node
= node
.childNodes
[0]
157 while not node
.nextSibling
:
158 node
= node
.parentNode
161 node
= node
.nextSibling
163 def size_request(self
, req
):
167 def do_update_now(self
):
168 # Update now, if we need to
169 if self
.update_timeout
:
170 g
.timeout_remove(self
.update_timeout
)
173 def update_all(self
, node
= None):
174 if self
.update_timeout
:
175 return # Going to update anyway...
177 if self
.view
.running():
178 self
.update_timeout
= g
.timeout_add(2000, self
.update
)
180 self
.update_timeout
= g
.timeout_add(10, self
.update
)
182 def move_from(self
, old
= []):
183 if self
.view
.current_nodes
:
185 for n
in self
.view
.current_nodes
:
188 for node
, bbox
, draw_fn
in self
.walk_tree(self
.ref_node
, self
.ref_pos
):
189 if bbox
[1] > self
.last_alloc
[1]: break # Off-screen
190 if bbox
[3] > 0 and node
in selection
:
192 break # A selected node is shown
194 print "(selected nodes not shown)"
195 self
.ref_node
= self
.view
.current_nodes
[0]
196 self
.ref_pos
= (40, self
.last_alloc
[1] / 2)
197 self
.backup_ref_node()
200 def set_view(self
, view
):
202 self
.view
.remove_display(self
)
204 self
.view
.add_display(self
)
207 def show_menu(self
, bev
):
210 def node_clicked(self
, node
, event
):
213 def xy_to_node(self
, x
, y
):
214 for (n
, (x1
, y1
, x2
, y2
)) in self
.drawn
.iteritems():
215 if x
>= x1
and x
<= x2
and y
>= y1
and y
<= y2
:
220 val
= (float(abs(x
)) ** 1.4)
226 if x
> 10: return x
- 10
227 if x
< -10: return x
+ 10
229 x
, y
, mask
= self
.window
.get_pointer()
230 sx
, sy
= self
.pan_start
231 dx
, dy
= scale(chop(x
- sx
)) / 20, scale(chop(y
- sy
))
232 dx
= max(dx
, 10 - self
.h_limits
[1])
233 dx
= min(dx
, self
.last_alloc
[0] - 10 - self
.h_limits
[0])
234 new
= [self
.ref_pos
[0] + dx
, self
.ref_pos
[1] + dy
]
236 if new
== self
.ref_pos
:
241 self
.backup_ref_node()
247 def backup_ref_node(self
):
248 self
.ref_pos
= list(self
.ref_pos
)
249 # Walk up the parents until we get a ref node above the start of the screen
250 # (redraw will come back down)
251 while self
.ref_pos
[1] > 0:
254 if self
.ref_node
.previousSibling
:
255 self
.ref_node
= self
.ref_node
.previousSibling
256 elif self
.ref_node
.parentNode
:
257 self
.ref_node
= self
.ref_node
.parentNode
261 # Walk from the parent node to find how far it is to this node...
262 for node
, bbox
, draw_fn
in self
.walk_tree(self
.ref_node
, (0, 0)):
263 if node
is src
: break
267 self
.ref_pos
[0] -= bbox
[0]
268 self
.ref_pos
[1] -= bbox
[1]
270 #print "(start from %s at (%d,%d))" % (self.ref_node, self.ref_pos[0], self.ref_pos[1])
272 if self
.ref_pos
[1] > 10:
274 elif self
.ref_pos
[1] < -100:
275 for node
, bbox
, draw_fn
in self
.walk_tree(self
.ref_node
, self
.ref_pos
):
276 if bbox
[3] > 10: break # Something is visible
278 self
.ref_pos
[1] = -100
280 def bg_event(self
, widget
, event
):
281 if event
.type == g
.gdk
.BUTTON_PRESS
and event
.button
== 3:
282 self
.show_menu(event
)
283 elif event
.type == g
.gdk
.BUTTON_PRESS
or event
.type == g
.gdk
._2BUTTON
_PRESS
:
285 node
= self
.xy_to_node(event
.x
, event
.y
)
286 if event
.button
== 1:
288 self
.node_clicked(node
, event
)
289 elif event
.button
== 2:
290 assert self
.pan_timeout
is None
291 self
.pan_start
= (event
.x
, event
.y
)
292 self
.pan_timeout
= g
.timeout_add(100, self
.pan
)
293 elif event
.type == g
.gdk
.BUTTON_RELEASE
and event
.button
== 2:
294 assert self
.pan_timeout
is not None
295 g
.timeout_remove(self
.pan_timeout
)
296 self
.pan_timeout
= None
301 def marked_changed(self
, nodes
):
302 "nodes is a list of nodes to be rechecked."