summaryrefslogtreecommitdiffstats
path: root/unit_trace/viz/viewer.py
diff options
context:
space:
mode:
Diffstat (limited to 'unit_trace/viz/viewer.py')
-rw-r--r--unit_trace/viz/viewer.py218
1 files changed, 109 insertions, 109 deletions
diff --git a/unit_trace/viz/viewer.py b/unit_trace/viz/viewer.py
index 909da76..efc79a1 100644
--- a/unit_trace/viz/viewer.py
+++ b/unit_trace/viz/viewer.py
@@ -13,10 +13,10 @@ import copy
13 13
14class GraphContextMenu(gtk.Menu): 14class GraphContextMenu(gtk.Menu):
15 MAX_STR_LEN = 80 15 MAX_STR_LEN = 80
16 16
17 def __init__(self, selected): 17 def __init__(self, selected):
18 super(GraphContextMenu, self).__init__() 18 super(GraphContextMenu, self).__init__()
19 19
20 for event in selected: 20 for event in selected:
21 string = str(event) 21 string = str(event)
22 if len(string) > GraphContextMenu.MAX_STR_LEN - 3: 22 if len(string) > GraphContextMenu.MAX_STR_LEN - 3:
@@ -24,100 +24,100 @@ class GraphContextMenu(gtk.Menu):
24 item = gtk.MenuItem(string) 24 item = gtk.MenuItem(string)
25 self.append(item) 25 self.append(item)
26 item.show() 26 item.show()
27 27
28class GraphArea(gtk.DrawingArea): 28class GraphArea(gtk.DrawingArea):
29 HORIZ_PAGE_SCROLL_FACTOR = 10.8 29 HORIZ_PAGE_SCROLL_FACTOR = 10.8
30 HORIZ_STEP_SCROLL_FACTOR = 0.8 30 HORIZ_STEP_SCROLL_FACTOR = 0.8
31 VERT_PAGE_SCROLL_FACTOR = 3.0 31 VERT_PAGE_SCROLL_FACTOR = 3.0
32 VERT_STEP_SCROLL_FACTOR = 0.5 32 VERT_STEP_SCROLL_FACTOR = 0.5
33 33
34 REFRESH_INFLATION_FACTOR = 20.0 34 REFRESH_INFLATION_FACTOR = 20.0
35 35
36 def __init__(self, renderer): 36 def __init__(self, renderer):
37 super(GraphArea, self).__init__() 37 super(GraphArea, self).__init__()
38 38
39 self.renderer = renderer 39 self.renderer = renderer
40 40
41 self.cur_x = 0 41 self.cur_x = 0
42 self.cur_y = 0 42 self.cur_y = 0
43 self.width = 0 43 self.width = 0
44 self.height = 0 44 self.height = 0
45 45
46 self.set_set_scroll_adjustments_signal('set-scroll-adjustments') 46 self.set_set_scroll_adjustments_signal('set-scroll-adjustments')
47 47
48 self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | 48 self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK |
49 gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.EXPOSURE_MASK) 49 gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.EXPOSURE_MASK)
50 50
51 self.band_rect = None 51 self.band_rect = None
52 self.ctrl_clicked = False 52 self.ctrl_clicked = False
53 self.dirtied_regions = [] 53 self.dirtied_regions = []
54 54
55 self.connect('expose-event', self.expose) 55 self.connect('expose-event', self.expose)
56 self.connect('size-allocate', self.size_allocate) 56 self.connect('size-allocate', self.size_allocate)
57 self.connect('set-scroll-adjustments', self.set_scroll_adjustments) 57 self.connect('set-scroll-adjustments', self.set_scroll_adjustments)
58 self.connect('button-press-event', self.button_press) 58 self.connect('button-press-event', self.button_press)
59 self.connect('button-release-event', self.button_release) 59 self.connect('button-release-event', self.button_release)
60 self.connect('motion-notify-event', self.motion_notify) 60 self.connect('motion-notify-event', self.motion_notify)
61 61
62 def expose(self, widget, expose_event, data=None): 62 def expose(self, widget, expose_event, data=None):
63 ctx = widget.window.cairo_create() 63 ctx = widget.window.cairo_create()
64 graph = self.renderer.get_graph() 64 graph = self.renderer.get_graph()
65 graph.update_view(self.cur_x, self.cur_y, self.width, self.height, ctx) 65 graph.update_view(self.cur_x, self.cur_y, self.width, self.height, ctx)
66 66
67 # We ourselves didn't update dirtied_regions, so this means that X or the 67 # We ourselves didn't update dirtied_regions, so this means that X or the
68 # window manager must have caused the expose event. So just update the 68 # window manager must have caused the expose event. So just update the
69 # expose_event's bounding area. 69 # expose_event's bounding area.
70 if not self.dirtied_regions or expose_event.send_event: 70 if not self.dirtied_regions or expose_event.send_event:
71 self.dirtied_regions = [(expose_event.area.x, expose_event.area.y, 71 self.dirtied_regions = [(expose_event.area.x, expose_event.area.y,
72 expose_event.area.width, expose_event.area.height)] 72 expose_event.area.width, expose_event.area.height)]
73 73
74 graph.render_surface(self.renderer.get_schedule(), self.dirtied_regions) 74 graph.render_surface(self.renderer.get_schedule(), self.dirtied_regions)
75 75
76 # render dragging band rectangle, if there is one 76 # render dragging band rectangle, if there is one
77 if self.band_rect is not None: 77 if self.band_rect is not None:
78 x, y, width, height = self.band_rect 78 x, y, width, height = self.band_rect
79 thickness = GraphFormat.BAND_THICKNESS 79 thickness = GraphFormat.BAND_THICKNESS
80 color = GraphFormat.BAND_COLOR 80 color = GraphFormat.BAND_COLOR
81 81
82 ctx.rectangle(x, y, width, height) 82 ctx.rectangle(x, y, width, height)
83 ctx.set_line_width(thickness) 83 ctx.set_line_width(thickness)
84 ctx.set_source_rgb(color[0], color[1], color[2]) 84 ctx.set_source_rgb(color[0], color[1], color[2])
85 ctx.stroke() 85 ctx.stroke()
86 86
87 self.dirtied_regions = [] 87 self.dirtied_regions = []
88 88
89 def get_renderer(self): 89 def get_renderer(self):
90 return self.renderer 90 return self.renderer
91 91
92 def get_graph(self): 92 def get_graph(self):
93 return self.renderer.get_graph() 93 return self.renderer.get_graph()
94 94
95 def set_scroll_adjustments(self, widget, horizontal, vertical, data=None): 95 def set_scroll_adjustments(self, widget, horizontal, vertical, data=None):
96 graph = self.renderer.get_graph() 96 graph = self.renderer.get_graph()
97 width = graph.get_width() 97 width = graph.get_width()
98 height = graph.get_height() 98 height = graph.get_height()
99 99
100 self.horizontal = horizontal 100 self.horizontal = horizontal
101 self.vertical = vertical 101 self.vertical = vertical
102 self.config_scrollbars(self.cur_x, self.cur_y) 102 self.config_scrollbars(self.cur_x, self.cur_y)
103 103
104 if self.horizontal is not None: 104 if self.horizontal is not None:
105 self.horizontal.connect('value-changed', self.horizontal_value_changed) 105 self.horizontal.connect('value-changed', self.horizontal_value_changed)
106 if self.vertical is not None: 106 if self.vertical is not None:
107 self.vertical.connect('value-changed', self.vertical_value_changed) 107 self.vertical.connect('value-changed', self.vertical_value_changed)
108 108
109 def horizontal_value_changed(self, adjustment): 109 def horizontal_value_changed(self, adjustment):
110 self.cur_x = min(adjustment.value, self.renderer.get_graph().get_width()) 110 self.cur_x = min(adjustment.value, self.renderer.get_graph().get_width())
111 self.cur_x = max(adjustment.value, 0.0) 111 self.cur_x = max(adjustment.value, 0.0)
112 112
113 self._dirty(0, 0, self.width, self.height) 113 self._dirty(0, 0, self.width, self.height)
114 114
115 def vertical_value_changed(self, adjustment): 115 def vertical_value_changed(self, adjustment):
116 self.cur_y = min(adjustment.value, self.renderer.get_graph().get_height()) 116 self.cur_y = min(adjustment.value, self.renderer.get_graph().get_height())
117 self.cur_y = max(adjustment.value, 0.0) 117 self.cur_y = max(adjustment.value, 0.0)
118 118
119 self._dirty(0, 0, self.width, self.height) 119 self._dirty(0, 0, self.width, self.height)
120 120
121 def size_allocate(self, widget, allocation): 121 def size_allocate(self, widget, allocation):
122 self.width = allocation.width 122 self.width = allocation.width
123 self.height = allocation.height 123 self.height = allocation.height
@@ -127,21 +127,21 @@ class GraphArea(gtk.DrawingArea):
127 graph = self.renderer.get_graph() 127 graph = self.renderer.get_graph()
128 width = graph.get_width() 128 width = graph.get_width()
129 height = graph.get_height() 129 height = graph.get_height()
130 130
131 if self.horizontal is not None: 131 if self.horizontal is not None:
132 self.horizontal.set_all(hvalue, 0.0, width, graph.get_attrs().maj_sep * GraphArea.HORIZ_STEP_SCROLL_FACTOR, 132 self.horizontal.set_all(hvalue, 0.0, width, graph.get_attrs().maj_sep * GraphArea.HORIZ_STEP_SCROLL_FACTOR,
133 graph.get_attrs().maj_sep * GraphArea.HORIZ_PAGE_SCROLL_FACTOR, self.width) 133 graph.get_attrs().maj_sep * GraphArea.HORIZ_PAGE_SCROLL_FACTOR, self.width)
134 if self.vertical is not None: 134 if self.vertical is not None:
135 self.vertical.set_all(vvalue, 0.0, height, graph.get_attrs().y_item_size * GraphArea.VERT_STEP_SCROLL_FACTOR, 135 self.vertical.set_all(vvalue, 0.0, height, graph.get_attrs().y_item_size * GraphArea.VERT_STEP_SCROLL_FACTOR,
136 graph.get_attrs().y_item_size * GraphArea.VERT_PAGE_SCROLL_FACTOR, self.height) 136 graph.get_attrs().y_item_size * GraphArea.VERT_PAGE_SCROLL_FACTOR, self.height)
137 137
138 def _find_max_layer(self, regions): 138 def _find_max_layer(self, regions):
139 max_layer = Canvas.BOTTOM_LAYER 139 max_layer = Canvas.BOTTOM_LAYER
140 for event in regions: 140 for event in regions:
141 if event.get_layer() > max_layer: 141 if event.get_layer() > max_layer:
142 max_layer = event.get_layer() 142 max_layer = event.get_layer()
143 return max_layer 143 return max_layer
144 144
145 def _update_event_changes(self, list1, list2): 145 def _update_event_changes(self, list1, list2):
146 # if an event changed selected status, update the bounding area 146 # if an event changed selected status, update the bounding area
147 for event in list1: 147 for event in list1:
@@ -152,12 +152,12 @@ class GraphArea(gtk.DrawingArea):
152 if event not in list1: 152 if event not in list1:
153 x, y, width, height = list2[event].get_dimensions() 153 x, y, width, height = list2[event].get_dimensions()
154 self._dirty_inflate(x - self.cur_x, y - self.cur_y, width, height, GraphFormat.BORDER_THICKNESS) 154 self._dirty_inflate(x - self.cur_x, y - self.cur_y, width, height, GraphFormat.BORDER_THICKNESS)
155 155
156 def motion_notify(self, widget, motion_event, data=None): 156 def motion_notify(self, widget, motion_event, data=None):
157 msg = None 157 msg = None
158 158
159 graph = self.renderer.get_graph() 159 graph = self.renderer.get_graph()
160 160
161 graph.render_surface(self.renderer.get_schedule(), [(motion_event.x, motion_event.y, 161 graph.render_surface(self.renderer.get_schedule(), [(motion_event.x, motion_event.y,
162 0, 0)], True) 162 0, 0)], True)
163 just_selected = graph.get_selected_regions(motion_event.x, motion_event.y, 0, 0) 163 just_selected = graph.get_selected_regions(motion_event.x, motion_event.y, 0, 0)
@@ -166,62 +166,62 @@ class GraphArea(gtk.DrawingArea):
166 the_event = None 166 the_event = None
167 else: 167 else:
168 max_layer = self._find_max_layer(just_selected) 168 max_layer = self._find_max_layer(just_selected)
169 169
170 for event in just_selected: 170 for event in just_selected:
171 if event.get_layer() == max_layer: 171 if event.get_layer() == max_layer:
172 the_event = event 172 the_event = event
173 break 173 break
174 174
175 msg = str(the_event) 175 msg = str(the_event)
176 176
177 self.emit('update-event-description', the_event, msg) 177 self.emit('update-event-description', the_event, msg)
178 178
179 if self.band_rect is not None: 179 if self.band_rect is not None:
180 selected = {} 180 selected = {}
181 was_selected = self.renderer.get_schedule().get_selected() 181 was_selected = self.renderer.get_schedule().get_selected()
182 if self.ctrl_clicked: 182 if self.ctrl_clicked:
183 selected = copy.copy(was_selected) 183 selected = copy.copy(was_selected)
184 184
185 # dragging a rectangle 185 # dragging a rectangle
186 x = self.band_rect[0] 186 x = self.band_rect[0]
187 y = self.band_rect[1] 187 y = self.band_rect[1]
188 width = motion_event.x - self.band_rect[0] 188 width = motion_event.x - self.band_rect[0]
189 height = motion_event.y - self.band_rect[1] 189 height = motion_event.y - self.band_rect[1]
190 190
191 x_p, y_p, width_p, height_p = self._positivify(x, y, width, height) 191 x_p, y_p, width_p, height_p = self._positivify(x, y, width, height)
192 graph.render_surface(self.renderer.get_schedule(), [(x_p, y_p, width_p, height_p)], True) 192 graph.render_surface(self.renderer.get_schedule(), [(x_p, y_p, width_p, height_p)], True)
193 selected.update(graph.get_selected_regions(x_p, y_p, width_p, height_p)) 193 selected.update(graph.get_selected_regions(x_p, y_p, width_p, height_p))
194 self.renderer.get_schedule().set_selected(selected) 194 self.renderer.get_schedule().set_selected(selected)
195 195
196 old_x, old_y, old_width, old_height = self.band_rect 196 old_x, old_y, old_width, old_height = self.band_rect
197 self.band_rect = (x, y, width, height) 197 self.band_rect = (x, y, width, height)
198 198
199 self._dirty_rect_border(old_x, old_y, old_width, old_height, GraphFormat.BAND_THICKNESS) 199 self._dirty_rect_border(old_x, old_y, old_width, old_height, GraphFormat.BAND_THICKNESS)
200 self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS) 200 self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS)
201 201
202 self._update_event_changes(was_selected, selected) 202 self._update_event_changes(was_selected, selected)
203 203
204 def button_press(self, widget, button_event, data=None): 204 def button_press(self, widget, button_event, data=None):
205 graph = self.renderer.get_graph() 205 graph = self.renderer.get_graph()
206 206
207 self.ctrl_clicked = button_event.state & gtk.gdk.CONTROL_MASK 207 self.ctrl_clicked = button_event.state & gtk.gdk.CONTROL_MASK
208 208
209 if button_event.button == 1: 209 if button_event.button == 1:
210 self.left_button_start_coor = (button_event.x, button_event.y) 210 self.left_button_start_coor = (button_event.x, button_event.y)
211 graph.render_surface(self.renderer.get_schedule(), \ 211 graph.render_surface(self.renderer.get_schedule(), \
212 [(button_event.x, button_event.y, 0, 0)], True) 212 [(button_event.x, button_event.y, 0, 0)], True)
213 213
214 just_selected = graph.get_selected_regions(button_event.x, button_event.y, 0, 0) 214 just_selected = graph.get_selected_regions(button_event.x, button_event.y, 0, 0)
215 215
216 max_layer = self._find_max_layer(just_selected) 216 max_layer = self._find_max_layer(just_selected)
217 217
218 new_now_selected = None 218 new_now_selected = None
219 was_selected = self.renderer.get_schedule().get_selected() 219 was_selected = self.renderer.get_schedule().get_selected()
220 if self.ctrl_clicked: 220 if self.ctrl_clicked:
221 new_now_selected = copy.copy(was_selected) 221 new_now_selected = copy.copy(was_selected)
222 else: 222 else:
223 new_now_selected = {} 223 new_now_selected = {}
224 224
225 # only select those events which were in the top layer (it's 225 # only select those events which were in the top layer (it's
226 # not intuitive to click something and then have something 226 # not intuitive to click something and then have something
227 # below it get selected). Also, clicking something that 227 # below it get selected). Also, clicking something that
@@ -237,43 +237,43 @@ class GraphArea(gtk.DrawingArea):
237 elif event in new_now_selected: 237 elif event in new_now_selected:
238 del new_now_selected[event] 238 del new_now_selected[event]
239 break # only pick one event when just clicking 239 break # only pick one event when just clicking
240 240
241 self.renderer.get_schedule().set_selected(new_now_selected) 241 self.renderer.get_schedule().set_selected(new_now_selected)
242 #self.last_selected = new_now_selected 242 #self.last_selected = new_now_selected
243 243
244 self._update_event_changes(new_now_selected, was_selected) 244 self._update_event_changes(new_now_selected, was_selected)
245 245
246 if self.band_rect is None: 246 if self.band_rect is None:
247 self.band_rect = (button_event.x, button_event.y, 0, 0) 247 self.band_rect = (button_event.x, button_event.y, 0, 0)
248 248
249 elif button_event.button == 3: 249 elif button_event.button == 3:
250 self._release_band() 250 self._release_band()
251 self.emit('request-context-menu', button_event, self.renderer.get_schedule().get_selected()) 251 self.emit('request-context-menu', button_event, self.renderer.get_schedule().get_selected())
252 252
253 def button_release(self, widget, button_event, data=None): 253 def button_release(self, widget, button_event, data=None):
254 self.ctrl_clicked = False 254 self.ctrl_clicked = False
255 #self.last_selected = copy.copy(self.renderer.get_schedule().get_selected()) 255 #self.last_selected = copy.copy(self.renderer.get_schedule().get_selected())
256 256
257 if button_event.button == 1: 257 if button_event.button == 1:
258 self._release_band() 258 self._release_band()
259 259
260 def _release_band(self): 260 def _release_band(self):
261 if self.band_rect is not None: 261 if self.band_rect is not None:
262 x, y, width, height = self.band_rect 262 x, y, width, height = self.band_rect
263 self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS) 263 self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS)
264 self.band_rect = None 264 self.band_rect = None
265 265
266 def _dirty(self, x, y, width, height): 266 def _dirty(self, x, y, width, height):
267 x = max(int(math.floor(x)), 0) 267 x = max(int(math.floor(x)), 0)
268 y = max(int(math.floor(y)), 0) 268 y = max(int(math.floor(y)), 0)
269 width = min(int(math.ceil(width)), self.width) 269 width = min(int(math.ceil(width)), self.width)
270 height = min(int(math.ceil(height)), self.height) 270 height = min(int(math.ceil(height)), self.height)
271 271
272 self.dirtied_regions.append((x, y, width, height)) 272 self.dirtied_regions.append((x, y, width, height))
273 273
274 rect = gtk.gdk.Rectangle(x, y, width, height) 274 rect = gtk.gdk.Rectangle(x, y, width, height)
275 self.window.invalidate_rect(rect, True) 275 self.window.invalidate_rect(rect, True)
276 276
277 def _dirty_inflate(self, x, y, width, height, thickness): 277 def _dirty_inflate(self, x, y, width, height, thickness):
278 t = thickness * GraphArea.REFRESH_INFLATION_FACTOR 278 t = thickness * GraphArea.REFRESH_INFLATION_FACTOR
279 x -= t / 2.0 279 x -= t / 2.0
@@ -281,17 +281,17 @@ class GraphArea(gtk.DrawingArea):
281 width += t 281 width += t
282 height += t 282 height += t
283 self._dirty(x, y, width, height) 283 self._dirty(x, y, width, height)
284 284
285 def _dirty_rect_border(self, x, y, width, height, thickness): 285 def _dirty_rect_border(self, x, y, width, height, thickness):
286 # support rectangles with negative width and height (i.e. -width = width, but going leftwards 286 # support rectangles with negative width and height (i.e. -width = width, but going leftwards
287 # instead of rightwards) 287 # instead of rightwards)
288 x, y, width, height = self._positivify(x, y, width, height) 288 x, y, width, height = self._positivify(x, y, width, height)
289 289
290 self._dirty_inflate(x, y, width, 0, thickness) 290 self._dirty_inflate(x, y, width, 0, thickness)
291 self._dirty_inflate(x, y, 0, height, thickness) 291 self._dirty_inflate(x, y, 0, height, thickness)
292 self._dirty_inflate(x, y + height, width, 0, thickness) 292 self._dirty_inflate(x, y + height, width, 0, thickness)
293 self._dirty_inflate(x + width, y, 0, height, thickness) 293 self._dirty_inflate(x + width, y, 0, height, thickness)
294 294
295 def _positivify(self, x, y, width, height): 295 def _positivify(self, x, y, width, height):
296 if width < 0: 296 if width < 0:
297 x += width 297 x += width
@@ -299,28 +299,28 @@ class GraphArea(gtk.DrawingArea):
299 if height < 0: 299 if height < 0:
300 y += height 300 y += height
301 height = -height 301 height = -height
302 302
303 return x, y, width, height 303 return x, y, width, height
304 304
305class GraphWindow(gtk.ScrolledWindow): 305class GraphWindow(gtk.ScrolledWindow):
306 def __init__(self, renderer): 306 def __init__(self, renderer):
307 super(GraphWindow, self).__init__(None, None) 307 super(GraphWindow, self).__init__(None, None)
308 308
309 self.add_events(gtk.gdk.KEY_PRESS_MASK) 309 self.add_events(gtk.gdk.KEY_PRESS_MASK)
310 310
311 self.ctr = 0 311 self.ctr = 0
312 self.connect('key-press-event', self.key_press) 312 self.connect('key-press-event', self.key_press)
313 313
314 self.garea = GraphArea(renderer) 314 self.garea = GraphArea(renderer)
315 self.add(self.garea) 315 self.add(self.garea)
316 self.garea.show() 316 self.garea.show()
317 317
318 def key_press(self, widget, key_event): 318 def key_press(self, widget, key_event):
319 hadj = self.get_hadjustment() 319 hadj = self.get_hadjustment()
320 vadj = self.get_vadjustment() 320 vadj = self.get_vadjustment()
321 if hadj is None or vadj is None: 321 if hadj is None or vadj is None:
322 return 322 return
323 323
324 hupper = hadj.get_upper() 324 hupper = hadj.get_upper()
325 hlower = hadj.get_lower() 325 hlower = hadj.get_lower()
326 hpincr = hadj.get_page_increment() 326 hpincr = hadj.get_page_increment()
@@ -333,9 +333,9 @@ class GraphWindow(gtk.ScrolledWindow):
333 vpincr = vadj.get_page_increment() 333 vpincr = vadj.get_page_increment()
334 vsincr = vadj.get_step_increment() 334 vsincr = vadj.get_step_increment()
335 vpsize = vadj.get_page_size() 335 vpsize = vadj.get_page_size()
336 336
337 ctrl_clicked = key_event.state & gtk.gdk.CONTROL_MASK 337 ctrl_clicked = key_event.state & gtk.gdk.CONTROL_MASK
338 338
339 adj_tuple = {'up' : (vadj, -vsincr, 0, vval, max), 339 adj_tuple = {'up' : (vadj, -vsincr, 0, vval, max),
340 'ctrl-up' : (vadj, -vpincr, 0, vval, max), 340 'ctrl-up' : (vadj, -vpincr, 0, vval, max),
341 'down' : (vadj, vsincr, vupper - vpsize, vval, min), 341 'down' : (vadj, vsincr, vupper - vpsize, vval, min),
@@ -344,78 +344,78 @@ class GraphWindow(gtk.ScrolledWindow):
344 'ctrl-left' : (hadj, -hpincr, 0, hval, max), 344 'ctrl-left' : (hadj, -hpincr, 0, hval, max),
345 'right' : (hadj, hsincr, hupper - hpsize, hval, min), 345 'right' : (hadj, hsincr, hupper - hpsize, hval, min),
346 'ctrl-right' : (hadj, hpincr, hupper - hpsize, hval, min)} 346 'ctrl-right' : (hadj, hpincr, hupper - hpsize, hval, min)}
347 347
348 keystr = None 348 keystr = None
349 keymap = {gtk.keysyms.Up : 'up', gtk.keysyms.Down : 'down', 349 keymap = {gtk.keysyms.Up : 'up', gtk.keysyms.Down : 'down',
350 gtk.keysyms.Left : 'left', gtk.keysyms.Right : 'right'} 350 gtk.keysyms.Left : 'left', gtk.keysyms.Right : 'right'}
351 if key_event.keyval in keymap: 351 if key_event.keyval in keymap:
352 keystr = keymap[key_event.keyval] 352 keystr = keymap[key_event.keyval]
353 353
354 if ctrl_clicked: 354 if ctrl_clicked:
355 keystr = 'ctrl-' + keystr 355 keystr = 'ctrl-' + keystr
356 356
357 if keystr is not None: 357 if keystr is not None:
358 adj, inc, lim, val, extr = adj_tuple[keystr] 358 adj, inc, lim, val, extr = adj_tuple[keystr]
359 adj.set_value(extr(val + inc, lim)) 359 adj.set_value(extr(val + inc, lim))
360 360
361 return True 361 return True
362 362
363 def get_graph_area(self): 363 def get_graph_area(self):
364 return self.garea 364 return self.garea
365 365
366class MainWindow(gtk.Window): 366class MainWindow(gtk.Window):
367 WINDOW_WIDTH_REQ = 500 367 WINDOW_WIDTH_REQ = 500
368 WINDOW_HEIGHT_REQ = 300 368 WINDOW_HEIGHT_REQ = 300
369 369
370 def __init__(self): 370 def __init__(self):
371 super(MainWindow, self).__init__(gtk.WINDOW_TOPLEVEL) 371 super(MainWindow, self).__init__(gtk.WINDOW_TOPLEVEL)
372 372
373 self.connect('delete_event', self.delete_event) 373 self.connect('delete_event', self.delete_event)
374 self.connect('destroy', self.die) 374 self.connect('destroy', self.die)
375 375
376 self.file_menu = gtk.Menu() 376 self.file_menu = gtk.Menu()
377 self.quit_item = gtk.MenuItem('_Quit', True) 377 self.quit_item = gtk.MenuItem('_Quit', True)
378 self.quit_item.connect('activate', self.quit_item_activate) 378 self.quit_item.connect('activate', self.quit_item_activate)
379 self.quit_item.show() 379 self.quit_item.show()
380 self.file_menu.append(self.quit_item) 380 self.file_menu.append(self.quit_item)
381 381
382 self.file_item = gtk.MenuItem('_File', True) 382 self.file_item = gtk.MenuItem('_File', True)
383 self.file_item.set_submenu(self.file_menu) 383 self.file_item.set_submenu(self.file_menu)
384 self.file_item.show() 384 self.file_item.show()
385 385
386 self.menu_bar = gtk.MenuBar() 386 self.menu_bar = gtk.MenuBar()
387 self.menu_bar.append(self.file_item) 387 self.menu_bar.append(self.file_item)
388 388
389 self.menu_bar.show() 389 self.menu_bar.show()
390 390
391 self.vbox = gtk.VBox(False, 0) 391 self.vbox = gtk.VBox(False, 0)
392 392
393 self.notebook = gtk.Notebook() 393 self.notebook = gtk.Notebook()
394 394
395 self.notebook.last_page = -1 395 self.notebook.last_page = -1
396 self.notebook.connect('switch-page', self.switch_page) 396 self.notebook.connect('switch-page', self.switch_page)
397 397
398 self.notebook.show() 398 self.notebook.show()
399 399
400 self.desc_label = gtk.Label('') 400 self.desc_label = gtk.Label('')
401 self.desc_label.set_justify(gtk.JUSTIFY_LEFT) 401 self.desc_label.set_justify(gtk.JUSTIFY_LEFT)
402 self.desc_label.show() 402 self.desc_label.show()
403 403
404 self.vbox.pack_start(self.menu_bar, False, False, 0) 404 self.vbox.pack_start(self.menu_bar, False, False, 0)
405 self.vbox.pack_start(self.notebook, True, True, 0) 405 self.vbox.pack_start(self.notebook, True, True, 0)
406 self.vbox.pack_start(self.desc_label, False, False, 0) 406 self.vbox.pack_start(self.desc_label, False, False, 0)
407 self.vbox.show() 407 self.vbox.show()
408 408
409 self.add(self.vbox) 409 self.add(self.vbox)
410 410
411 self.set_size_request(MainWindow.WINDOW_WIDTH_REQ, MainWindow.WINDOW_HEIGHT_REQ) 411 self.set_size_request(MainWindow.WINDOW_WIDTH_REQ, MainWindow.WINDOW_HEIGHT_REQ)
412 412
413 self.show() 413 self.show()
414 414
415 def connect_widgets(self, garea): 415 def connect_widgets(self, garea):
416 garea.connect('update-event-description', self.update_event_description) 416 garea.connect('update-event-description', self.update_event_description)
417 garea.connect('request-context-menu', self.request_context_menu) 417 garea.connect('request-context-menu', self.request_context_menu)
418 418
419 def set_renderers(self, renderers): 419 def set_renderers(self, renderers):
420 for i in range(0, self.notebook.get_n_pages()): 420 for i in range(0, self.notebook.get_n_pages()):
421 self.notebook.remove_page(0) 421 self.notebook.remove_page(0)
@@ -424,7 +424,7 @@ class MainWindow(gtk.Window):
424 self.connect_widgets(gwindow.get_graph_area()) 424 self.connect_widgets(gwindow.get_graph_area())
425 gwindow.show() 425 gwindow.show()
426 self.notebook.append_page(gwindow, gtk.Label(title)) 426 self.notebook.append_page(gwindow, gtk.Label(title))
427 427
428 def switch_page(self, widget, page, page_num): 428 def switch_page(self, widget, page, page_num):
429 if self.notebook.get_nth_page(self.notebook.last_page) is not None: 429 if self.notebook.get_nth_page(self.notebook.last_page) is not None:
430 old_value = self.notebook.get_nth_page(self.notebook.last_page).get_hadjustment().get_value() 430 old_value = self.notebook.get_nth_page(self.notebook.last_page).get_hadjustment().get_value()
@@ -432,27 +432,27 @@ class MainWindow(gtk.Window):
432 new_ofs = self.notebook.get_nth_page(page_num).get_graph_area().get_graph().get_origin()[0] 432 new_ofs = self.notebook.get_nth_page(page_num).get_graph_area().get_graph().get_origin()[0]
433 new_value = old_value - old_ofs + new_ofs 433 new_value = old_value - old_ofs + new_ofs
434 self.notebook.get_nth_page(page_num).get_hadjustment().set_value(new_value) 434 self.notebook.get_nth_page(page_num).get_hadjustment().set_value(new_value)
435 435
436 self.notebook.last_page = page_num 436 self.notebook.last_page = page_num
437 437
438 def update_event_description(self, widget, event, msg): 438 def update_event_description(self, widget, event, msg):
439 self.desc_label.set_text(msg) 439 self.desc_label.set_text(msg)
440 440
441 def request_context_menu(self, widget, gdk_event, selected): 441 def request_context_menu(self, widget, gdk_event, selected):
442 button = 0 442 button = 0
443 if hasattr(gdk_event, 'button'): 443 if hasattr(gdk_event, 'button'):
444 button = gdk_event.button 444 button = gdk_event.button
445 time = gdk_event.time 445 time = gdk_event.time
446 446
447 menu = GraphContextMenu(selected) 447 menu = GraphContextMenu(selected)
448 menu.popup(None, None, None, button, time) 448 menu.popup(None, None, None, button, time)
449 449
450 def quit_item_activate(self, widget): 450 def quit_item_activate(self, widget):
451 self.destroy() 451 self.destroy()
452 452
453 def delete_event(self, widget, event, data=None): 453 def delete_event(self, widget, event, data=None):
454 return False 454 return False
455 455
456 def die(self, widget, data=None): 456 def die(self, widget, data=None):
457 gtk.main_quit() 457 gtk.main_quit()
458 458