[go: up one dir, main page]

Menu

[390b88]: / ui / boxview.py  Maximize  Restore  History

Download this file

210 lines (165 with data), 5.5 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
'''Box viewing.'''
import gtk
import pango
import box
import ir.pprint
from ui.menus import PopupMenu
class Range:
def __init__(self, path, start, end = None):
self.path = path
self.start = start
self.end = end
self.subranges = []
def __cmp__(self, other):
return cmp(self.start, other.start)
def contains(self, set):
return self.start <= set <= self.end
def contains_range(self, start, endiff):
return self.contains(start) and self.contains(end)
def get_path_at_offset(self, offset):
if not self.contains(offset):
return None
for subrange in self.subranges:
path = subrange.get_path_at_offset(offset)
if path is not None:
return path
return self.path
def get_range_at_path(self, path):
# TODO: use a hash table
if self.path == path:
return self.start, self.end
for subrange in self.subranges:
result = subrange.get_range_at_path(path)
if result is not None:
return result
return None
class TextBufferFormatter(box.Formatter):
'''Formats into a TextBuffer.'''
# See hypertext.py example included in pygtk distribution
def __init__(self, buffer):
box.Formatter.__init__(self)
self.buffer = buffer
self.buffer.set_text("", 0)
self.iter = self.buffer.get_iter_at_offset(0)
self.types = {}
self.types['operator'] = self.buffer.create_tag(None,
foreground = 'black'
)
self.types['keyword'] = self.buffer.create_tag(None,
foreground = 'black',
weight=pango.WEIGHT_BOLD
)
self.types['literal'] = self.buffer.create_tag(None,
foreground = 'dark blue',
#foreground = 'green',
#style=pango.STYLE_ITALIC,
)
self.types['symbol'] = self.buffer.create_tag(None,
foreground = 'dark blue',
style=pango.STYLE_ITALIC,
)
self.default_highlight_tag = self.buffer.create_tag(None)
self.highlight_tag_stack = [self.default_highlight_tag]
default_path_tag = self.buffer.create_tag(None)
self.range_stack = []
def write(self, s):
highlight_tag = self.highlight_tag_stack[-1]
self.buffer.insert_with_tags(self.iter, s, highlight_tag)
def handle_tag_start(self, name, value):
if name == 'type':
highlight_tag = self.types.get(value, self.default_highlight_tag)
self.highlight_tag_stack.append(highlight_tag)
if name == 'path':
range = Range(value, self.get_offset())
self.range_stack.append(range)
def handle_tag_end(self, name):
if name == 'type':
self.highlight_tag_stack.pop()
if name == 'path':
assert self.range_stack
range = self.range_stack.pop()
assert range.end is None
range.end = self.get_offset()
if self.range_stack:
self.range_stack[-1].subranges.append(range)
else:
self.buffer.range = range
self.buffer.path_range[range.path] = range.start, range.end
def get_offset(self):
# TODO: keep track of offset
return self.buffer.get_iter_at_mark(self.buffer.get_insert()).get_offset()
class BoxBuffer(gtk.TextBuffer):
def __init__(self, model):
gtk.TextBuffer.__init__(self, None)
self.model = model
self.range = None
self.path_range = {}
model.connect('notify::term', self.on_term_update)
model.connect('notify::selection', self.on_selection_update)
def on_term_update(self, term):
boxes = ir.pprint.module(term)
self.set_text("")
self.range = None
self.path_range = {}
formatter = TextBufferFormatter(self)
box.write(boxes, formatter)
self.place_cursor(self.get_start_iter())
def on_selection_update(self, selection):
start, end = selection
if start or end:
# TODO: this is often unnecessary
try:
start, dummy = self.get_iters_at_path(start)
dummy, end = self.get_iters_at_path(end)
except Exception, ex:
print ex
return
else:
start = end = self.get_start_iter()
self.select_range(start, end)
def get_path_at_iter(self, iter):
if self.range is None:
return None
off = iter.get_offset()
path = self.range.get_path_at_offset(off)
return path
def get_iters_at_path(self, path):
try:
start, end = self.path_range[path]
except KeyError:
return None
start = self.get_iter_at_offset(start)
end = self.get_iter_at_offset(end)
return start, end
class BoxView(gtk.TextView):
def __init__(self, model):
gtk.TextView.__init__(self, BoxBuffer(model))
self.model = model
self.set_editable(False)
self.connect("event", self.on_button_press)
def on_button_press(self, textview, event):
'''Update the selection paths.'''
buffer = textview.get_buffer()
start = buffer.get_iter_at_mark(buffer.get_selection_bound())
end = buffer.get_iter_at_mark(buffer.get_insert())
if event.type == gtk.gdk.BUTTON_RELEASE and event.button == 1:
start = buffer.get_path_at_iter(start)
end = buffer.get_path_at_iter(end)
self.model.set_selection((start, end))
return False
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
x, y = textview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, int(event.x), int(event.y))
iter = textview.get_iter_at_location(x, y)
#print start.get_offset(), end.get_offset()
if iter.in_range(start, end):
# user clicked inside the selected range
start = buffer.get_path_at_iter(start)
end = buffer.get_path_at_iter(end)
else:
# user clicked outside the selected range
path = buffer.get_path_at_iter(iter)
self.model.set_selection((path, path))
popupmenu = PopupMenu(self.model)
popupmenu.popup( None, None, None, event.button, event.time)
return True
return False