diff options
Diffstat (limited to 'viz/viewer.py')
| -rw-r--r-- | viz/viewer.py | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/viz/viewer.py b/viz/viewer.py new file mode 100644 index 0000000..a695473 --- /dev/null +++ b/viz/viewer.py | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | #!/usr/bin/python | ||
| 2 | |||
| 3 | """GUI stuff.""" | ||
| 4 | |||
| 5 | from schedule import * | ||
| 6 | from renderer import * | ||
| 7 | |||
| 8 | import pygtk | ||
| 9 | import gtk | ||
| 10 | import gobject | ||
| 11 | |||
| 12 | class GraphArea(gtk.DrawingArea): | ||
| 13 | DAREA_WIDTH_REQ = 500 | ||
| 14 | DAREA_HEIGHT_REQ = 300 | ||
| 15 | HORIZ_PAGE_SCROLL_FACTOR = 4.8 | ||
| 16 | HORIZ_STEP_SCROLL_FACTOR = 0.8 | ||
| 17 | VERT_PAGE_SCROLL_FACTOR = 3.0 | ||
| 18 | VERT_STEP_SCROLL_FACTOR = 0.5 | ||
| 19 | |||
| 20 | def __init__(self, renderer): | ||
| 21 | super(GraphArea, self).__init__() | ||
| 22 | |||
| 23 | self.renderer = renderer | ||
| 24 | |||
| 25 | self.cur_x = 0 | ||
| 26 | self.cur_y = 0 | ||
| 27 | self.width = 0 | ||
| 28 | self.height = 0 | ||
| 29 | |||
| 30 | self.now_selected = [] | ||
| 31 | |||
| 32 | self.set_set_scroll_adjustments_signal('set-scroll-adjustments') | ||
| 33 | |||
| 34 | self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK) | ||
| 35 | |||
| 36 | self.connect('expose-event', self.expose) | ||
| 37 | self.connect('size-allocate', self.size_allocate) | ||
| 38 | self.connect('set-scroll-adjustments', self.set_scroll_adjustments) | ||
| 39 | self.connect('button-press-event', self.button_press) | ||
| 40 | self.connect('motion-notify-event', self.motion_notify) | ||
| 41 | |||
| 42 | self.set_size_request(GraphArea.DAREA_WIDTH_REQ, GraphArea.DAREA_HEIGHT_REQ) | ||
| 43 | |||
| 44 | def expose(self, widget, event, data=None): | ||
| 45 | ctx = widget.window.cairo_create() | ||
| 46 | graph = self.renderer.get_graph() | ||
| 47 | graph.update_view(self.cur_x, self.cur_y, self.width, self.height, ctx) | ||
| 48 | graph.render_surface(self.renderer.get_schedule()) | ||
| 49 | |||
| 50 | def set_scroll_adjustments(self, widget, horizontal, vertical, data=None): | ||
| 51 | graph = self.renderer.get_graph() | ||
| 52 | width = graph.get_width() | ||
| 53 | height = graph.get_height() | ||
| 54 | |||
| 55 | self.horizontal = horizontal | ||
| 56 | self.vertical = vertical | ||
| 57 | self.config_scrollbars(self.cur_x, self.cur_y) | ||
| 58 | |||
| 59 | self.horizontal.connect('value-changed', self.horizontal_value_changed) | ||
| 60 | self.vertical.connect('value-changed', self.vertical_value_changed) | ||
| 61 | |||
| 62 | def horizontal_value_changed(self, adjustment): | ||
| 63 | self.cur_x = min(adjustment.value, self.renderer.get_graph().get_width()) | ||
| 64 | self.cur_x = max(adjustment.value, 0.0) | ||
| 65 | |||
| 66 | rect = gtk.gdk.Rectangle(0, 0, self.width, self.height) | ||
| 67 | self.window.invalidate_rect(rect, True) | ||
| 68 | |||
| 69 | def vertical_value_changed(self, adjustment): | ||
| 70 | self.cur_y = min(adjustment.value, self.renderer.get_graph().get_height()) | ||
| 71 | self.cur_y = max(adjustment.value, 0.0) | ||
| 72 | |||
| 73 | rect = gtk.gdk.Rectangle(0, 0, self.width, self.height) | ||
| 74 | self.window.invalidate_rect(rect, True) | ||
| 75 | |||
| 76 | def size_allocate(self, widget, allocation): | ||
| 77 | self.width = allocation.width | ||
| 78 | self.height = allocation.height | ||
| 79 | self.config_scrollbars(self.cur_x, self.cur_y) | ||
| 80 | |||
| 81 | def config_scrollbars(self, hvalue, vvalue): | ||
| 82 | graph = self.renderer.get_graph() | ||
| 83 | width = graph.get_width() | ||
| 84 | height = graph.get_height() | ||
| 85 | |||
| 86 | if self.horizontal is not None: | ||
| 87 | self.horizontal.set_all(hvalue, 0.0, width, graph.get_attrs().maj_sep * GraphArea.HORIZ_STEP_SCROLL_FACTOR, | ||
| 88 | graph.get_attrs().maj_sep * GraphArea.HORIZ_PAGE_SCROLL_FACTOR, self.width) | ||
| 89 | if self.vertical is not None: | ||
| 90 | self.vertical.set_all(vvalue, 0.0, height, graph.get_attrs().y_item_size * GraphArea.VERT_STEP_SCROLL_FACTOR, | ||
| 91 | graph.get_attrs().y_item_size * GraphArea.VERT_PAGE_SCROLL_FACTOR, self.height) | ||
| 92 | |||
| 93 | def _find_max_layer(self, regions): | ||
| 94 | max_layer = Canvas.BOTTOM_LAYER | ||
| 95 | for event in regions: | ||
| 96 | if event.get_layer() > max_layer: | ||
| 97 | max_layer = event.get_layer() | ||
| 98 | return max_layer | ||
| 99 | |||
| 100 | def motion_notify(self, widget, motion_event, data=None): | ||
| 101 | msg = None | ||
| 102 | |||
| 103 | graph = self.renderer.get_graph() | ||
| 104 | just_selected = graph.get_selected_regions(motion_event.x, motion_event.y) | ||
| 105 | if not just_selected: | ||
| 106 | msg = '' | ||
| 107 | the_event = None | ||
| 108 | else: | ||
| 109 | max_layer = self._find_max_layer(just_selected) | ||
| 110 | |||
| 111 | for event in just_selected: | ||
| 112 | if event.get_layer() == max_layer: | ||
| 113 | the_event = event | ||
| 114 | break | ||
| 115 | |||
| 116 | msg = str(the_event) | ||
| 117 | |||
| 118 | self.emit('update-event-description', the_event, msg) | ||
| 119 | |||
| 120 | def button_press(self, widget, button_event, data=None): | ||
| 121 | graph = self.renderer.get_graph() | ||
| 122 | |||
| 123 | if button_event.button == 1: | ||
| 124 | just_selected = graph.get_selected_regions(button_event.x, button_event.y) | ||
| 125 | |||
| 126 | max_layer = self._find_max_layer(just_selected) | ||
| 127 | |||
| 128 | # only select those events which were in the top layer (it's | ||
| 129 | # not intuitive to click something and then have something | ||
| 130 | # below it get selected). Also, clicking something that | ||
| 131 | # is selected deselects it | ||
| 132 | new_now_selected = {} | ||
| 133 | for event in just_selected: | ||
| 134 | if event.get_layer() == max_layer: | ||
| 135 | if not event.is_selected(): | ||
| 136 | new_now_selected[event] = None | ||
| 137 | event.set_selected(not event.is_selected()) | ||
| 138 | break | ||
| 139 | |||
| 140 | for event in self.now_selected: | ||
| 141 | if event not in new_now_selected: | ||
| 142 | event.set_selected(False) | ||
| 143 | |||
| 144 | self.now_selected = new_now_selected | ||
| 145 | |||
| 146 | rect = gtk.gdk.Rectangle(0, 0, self.width, self.height) | ||
| 147 | self.window.invalidate_rect(rect, True) | ||
| 148 | |||
| 149 | class GraphWindow(gtk.ScrolledWindow): | ||
| 150 | def __init__(self, renderer): | ||
| 151 | super(GraphWindow, self).__init__(None, None) | ||
| 152 | |||
| 153 | self.garea = GraphArea(renderer) | ||
| 154 | self.add(self.garea) | ||
| 155 | self.garea.show() | ||
| 156 | |||
| 157 | def get_graph_area(self): | ||
| 158 | return self.garea | ||
| 159 | |||
| 160 | class MainWindow(object): | ||
| 161 | def __init__(self, renderer): | ||
| 162 | self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) | ||
| 163 | |||
| 164 | self.window.connect('delete_event', self.delete_event) | ||
| 165 | self.window.connect('destroy', self.destroy) | ||
| 166 | |||
| 167 | self.vbox = gtk.VBox(False, 0) | ||
| 168 | |||
| 169 | self.gwindow = GraphWindow(renderer) | ||
| 170 | self.gwindow.get_graph_area().connect('update-event-description', | ||
| 171 | self.update_event_description) | ||
| 172 | self.gwindow.show() | ||
| 173 | |||
| 174 | self.desc_label = gtk.Label('') | ||
| 175 | self.desc_label.set_justify(gtk.JUSTIFY_LEFT) | ||
| 176 | self.desc_label.show() | ||
| 177 | |||
| 178 | self.vbox.pack_start(self.gwindow, True, True, 0) | ||
| 179 | self.vbox.pack_start(self.desc_label, False, False, 0) | ||
| 180 | self.vbox.show() | ||
| 181 | |||
| 182 | self.window.add(self.vbox) | ||
| 183 | self.window.show() | ||
| 184 | |||
| 185 | def update_event_description(self, widget, event, msg): | ||
| 186 | self.desc_label.set_text(msg) | ||
| 187 | |||
| 188 | def delete_event(self, widget, event, data=None): | ||
| 189 | return False | ||
| 190 | |||
| 191 | def destroy(self, widget, data=None): | ||
| 192 | gtk.main_quit() | ||
| 193 | |||
