Make the view follow the cursor.
[dom-editor.git] / Dome / Display2.py
bloba05ab59dd82b45f5c1d07d2eb084e4a8cb3f7969
1 import rox
2 from rox import g
3 from xml.dom import Node
5 def init_colours(window, gc):
6 global black
7 black = gc
9 class GUINode:
10 def __init__(self, widget, node):
11 self.widget = widget
12 self.node = node
13 self.text = self.get_text(node)
14 self.layout = widget.create_pango_layout(self.text)
15 w, h = self.layout.get_pixel_size()
16 self.text_width = w
17 self.text_height = h
18 self.bbox = [w + 12, max(h, 8)]
19 self.kids = []
21 def render(self, widget, x, y):
22 surface = widget.pm
23 fg = widget.style.fg_gc
24 bg = widget.style.bg_gc
25 surface.draw_rectangle(fg[g.STATE_NORMAL], True,
26 x, y, 8, self.text_height - 1)
28 if self.node in self.widget.selection:
29 surface.draw_rectangle(bg[g.STATE_SELECTED], True,
30 x + 12, y, self.text_width - 1, self.text_height - 1)
31 surface.draw_layout(fg[g.STATE_SELECTED], x + 12, y, self.layout)
32 else:
33 surface.draw_layout(fg[g.STATE_NORMAL], x + 12, y, self.layout)
35 def get_text(self, node):
36 if node.nodeType == Node.TEXT_NODE:
37 return node.nodeValue.strip()
38 elif node.nodeType == Node.ELEMENT_NODE:
39 return node.nodeName
40 elif node.nodeType == Node.COMMENT_NODE:
41 return node.nodeValue.strip()
42 elif node.nodeName:
43 return node.nodeName
44 elif node.nodeValue:
45 return '<noname>' + node.nodeValue
46 else:
47 return '<unknown>'
49 def add_child(self, child):
50 # Add child GUINode, and return start point for next child.
51 # If child is None, return the first free point, but still update
52 # space needed (for initial connector).
53 if not self.kids:
54 self.new_child_pos = [16, max(16, self.text_height + 2)]
55 self.bbox = [max(self.bbox[0], self.new_child_pos[0]),
56 max(self.bbox[1], self.new_child_pos[1])]
58 if child:
59 self.bbox[1] += child.bbox[1]
60 self.bbox[0] = max(self.bbox[0],
61 child.bbox[0] + self.new_child_pos[0])
62 self.new_child_pos[1] += child.bbox[1]
63 self.kids.append(child)
64 return self.new_child_pos
66 class Display(g.EventBox):
67 def __init__(self, window, view):
68 g.EventBox.__init__(self)
69 self.set_app_paintable(True)
70 self.set_double_buffered(False)
71 self.update_timeout = 0
73 self.view = None
74 self.parent_window = window
75 self.pm = None
77 s = self.get_style().copy()
78 s.bg[g.STATE_NORMAL] = g.gdk.color_parse('old lace')
79 self.set_style(s)
81 #self.connect('destroy', self.destroyed)
82 self.connect('button-press-event', self.bg_event)
84 #self.set_view(view)
86 #rox.app_options.add_notify(self.options_changed)
88 # Display is relative to this node
89 self.ref_node = view.root
90 self.scroll_offset = (0, 0) # 0,0 => ref node at top-left
92 self.last_alloc = None
93 self.connect('size-allocate', lambda w, a: self.size_allocate(a))
94 self.connect('size-request', lambda w, r: self.size_request(r))
95 self.connect('expose-event', lambda w, e: 1)
97 self.set_view(view)
99 def size_allocate(self, alloc):
100 init_colours(self.window, self.style.black_gc)
101 new = (alloc.width, alloc.height)
102 if self.last_alloc == new:
103 return
104 self.last_alloc = new
105 assert self.window
106 #print "Alloc", alloc.width, alloc.height
107 pm = g.gdk.Pixmap(self.window, alloc.width, alloc.height, -1)
108 self.window.set_back_pixmap(pm, False)
109 self.pm = pm
110 self.update()
112 def update(self):
113 if not self.pm: return
114 print "update"
115 if self.view.current_nodes:
116 self.ref_node = self.view.current_nodes[0] # XXX
118 self.update_timeout = 0
120 self.pm.draw_rectangle(self.style.bg_gc[g.STATE_NORMAL], True,
121 0, 0, self.last_alloc[0], self.last_alloc[1])
123 self.drawn = {} # xmlNode -> GUINode
125 self.selection = {}
126 for n in self.view.current_nodes:
127 self.selection[n] = None
128 self.add_node(self.ref_node, self.scroll_offset[0], self.scroll_offset[1])
130 self.window.clear()
132 return 0
134 def size_request(self, req):
135 req.width = 4
136 req.height = 4
138 def add_node(self, node, x, y):
139 gn = GUINode(self, node)
140 self.drawn[node] = gn
141 gn.render(self, x, y)
143 c = None
144 for k in node.childNodes:
145 cx, cy = gn.add_child(c)
146 cx += x
147 cy += y
148 if cx > self.last_alloc[0] or cy > self.last_alloc[1]:
149 return gn
150 c = self.add_node(k, cx, cy)
151 gn.add_child(c)
152 return gn
154 def do_update_now(self):
155 # Update now, if we need to
156 if self.update_timeout:
157 g.timeout_remove(self.update_timeout)
158 self.update()
160 def update_all(self, node = None):
161 if self.update_timeout:
162 return # Going to update anyway...
164 if self.view.running():
165 self.update_timeout = g.timeout_add(2000, self.update)
166 else:
167 self.update_timeout = g.timeout_add(10, self.update)
169 def move_from(self, old = []):
170 self.update_all()
172 def set_view(self, view):
173 if self.view:
174 self.view.remove_display(self)
175 self.view = view
176 self.view.add_display(self)
177 self.update_all()
179 def show_menu(self, bev):
180 pass
182 def bg_event(self, widget, event):
183 if event.type == g.gdk.BUTTON_PRESS and event.button == 3:
184 self.show_menu(event)
185 return 1