summaryrefslogtreecommitdiffstats
path: root/unit_trace/viz/viewer.py
diff options
context:
space:
mode:
authorGary Bressler <garybressler@nc.rr.com>2010-04-27 14:04:50 -0400
committerGary Bressler <garybressler@nc.rr.com>2010-04-27 14:04:50 -0400
commitdf6c90f22f5cdd5b079a9a69a54f30104eab9146 (patch)
treedb68985cc6858faaab1728aa8972e298266b837f /unit_trace/viz/viewer.py
parente3a1e19e87dbb3df413015bfc714283bc8602999 (diff)
Colorsgit add .! COLORSgit add .git add .geany index.txt
Diffstat (limited to 'unit_trace/viz/viewer.py')
-rw-r--r--unit_trace/viz/viewer.py264
1 files changed, 210 insertions, 54 deletions
diff --git a/unit_trace/viz/viewer.py b/unit_trace/viz/viewer.py
index 5e707b8..33c84ff 100644
--- a/unit_trace/viz/viewer.py
+++ b/unit_trace/viz/viewer.py
@@ -4,7 +4,10 @@
4 4
5from schedule import * 5from schedule import *
6from renderer import * 6from renderer import *
7from graph import *
8from canvas import *
7from windows import * 9from windows import *
10from format import *
8 11
9import pygtk 12import pygtk
10import gtk 13import gtk
@@ -79,6 +82,23 @@ class GraphArea(gtk.DrawingArea):
79 self.connect('button-release-event', self.button_release) 82 self.connect('button-release-event', self.button_release)
80 self.connect('motion-notify-event', self.motion_notify) 83 self.connect('motion-notify-event', self.motion_notify)
81 84
85 def output_to_file(self, filename, ftype):
86 """Outputs the entire graph to a file."""
87 graph = self.renderer.get_graph()
88 surface = None
89 if ftype == 'png':
90 surface = ImageSurface()
91 elif ftype == 'svg':
92 surface = SVGSurface()
93 else:
94 raise ValueError
95
96 surface.renew(graph.get_width(), graph.get_height())
97 graph.set_tmp_surface(surface)
98 graph.render_all(self.renderer.get_schedule())
99 surface.write_out(filename)
100 graph.revert_surface()
101
82 def expose(self, widget, expose_event, data=None): 102 def expose(self, widget, expose_event, data=None):
83 ctx = widget.window.cairo_create() 103 ctx = widget.window.cairo_create()
84 graph = self.renderer.get_graph() 104 graph = self.renderer.get_graph()
@@ -204,7 +224,11 @@ class GraphArea(gtk.DrawingArea):
204 graph.get_attrs().y_item_size * GraphArea.VERT_PAGE_SCROLL_FACTOR / scale, 224 graph.get_attrs().y_item_size * GraphArea.VERT_PAGE_SCROLL_FACTOR / scale,
205 self.height / scale) 225 self.height / scale)
206 self.set_vvalue(vvalue) 226 self.set_vvalue(vvalue)
207 227
228 def refresh_all(self):
229 """Refreshes the entire visible screen."""
230 self._dirty(0, 0, self.width, self.height)
231
208 def refresh_events(self, sender, new, old, replace): 232 def refresh_events(self, sender, new, old, replace):
209 """Even if the selected areas change on one graph, they change 233 """Even if the selected areas change on one graph, they change
210 everywhere, and different events might be in different regions on 234 everywhere, and different events might be in different regions on
@@ -216,7 +240,7 @@ class GraphArea(gtk.DrawingArea):
216 refreshes the drawing of the graph that requested the change.""" 240 refreshes the drawing of the graph that requested the change."""
217 if self is not sender: 241 if self is not sender:
218 self.renderer.get_graph().render_events(new, True) 242 self.renderer.get_graph().render_events(new, True)
219 243
220 self._tag_events(new) 244 self._tag_events(new)
221 245
222 if self is sender: 246 if self is sender:
@@ -228,20 +252,23 @@ class GraphArea(gtk.DrawingArea):
228 else: 252 else:
229 self.renderer.get_schedule().remove_selected(old) 253 self.renderer.get_schedule().remove_selected(old)
230 self.renderer.get_schedule().add_selected(new) 254 self.renderer.get_schedule().add_selected(new)
255
256 self.emit('update-sel-changes', self.renderer.get_schedule().get_selected())
231 257
232 def _find_max_layer(self, regions): 258 def _find_max_layer(self, regions):
233 max_layer = Canvas.BOTTOM_LAYER 259 max_layer = -1
234 for event in regions: 260 for layer in regions:
235 if event.get_layer() > max_layer: 261 if layer > max_layer:
236 max_layer = event.get_layer() 262 max_layer = layer
237 return max_layer 263 return max_layer
238 264
239 def _dirty_events(self, events): 265 def _dirty_events(self, events):
240 # if an event changed selected status, update the bounding area 266 # if an event changed selected status, update the bounding area
241 for layer in events: 267 for layer in events:
242 for event in events[layer]: 268 for event in events[layer]:
243 x, y, width, height = events[layer][event][self].get_dimensions() 269 if not events[layer][event][self].is_dummy():
244 self._dirty_inflate((x - self.cur_x) * self.scale, 270 x, y, width, height = events[layer][event][self].get_dimensions()
271 self._dirty_inflate((x - self.cur_x) * self.scale,
245 (y - self.cur_y) * self.scale, 272 (y - self.cur_y) * self.scale,
246 width * self.scale, 273 width * self.scale,
247 height * self.scale, 274 height * self.scale,
@@ -284,15 +311,14 @@ class GraphArea(gtk.DrawingArea):
284 graph.render_surface(self.renderer.get_schedule(), [(motion_event.x, motion_event.y, 311 graph.render_surface(self.renderer.get_schedule(), [(motion_event.x, motion_event.y,
285 0, 0)], True) 312 0, 0)], True)
286 313
287 just_selected = graph.get_selected_regions(motion_event.x, motion_event.y, 0, 0) 314 just_selected = graph.get_intersecting_regions(motion_event.x, motion_event.y, 0, 0)
288 was_selected = self.renderer.get_schedule().get_selected() 315 was_selected = self.renderer.get_schedule().get_selected()
289 if not just_selected: 316 if not just_selected:
290 msg = '' 317 msg = ''
291 the_event = None 318 the_event = None
292 else: 319 else:
293 max_layer = self._find_max_layer(just_selected) 320 max_layer = self._find_max_layer(just_selected)
294 321 for event in just_selected[max_layer]:
295 for event in just_selected:
296 if event.get_layer() == max_layer: 322 if event.get_layer() == max_layer:
297 the_event = event 323 the_event = event
298 break 324 break
@@ -331,9 +357,11 @@ class GraphArea(gtk.DrawingArea):
331 graph.render_surface(self.renderer.get_schedule(), dirty_list, True) 357 graph.render_surface(self.renderer.get_schedule(), dirty_list, True)
332 for rect in dirty_list: 358 for rect in dirty_list:
333 rx, ry, rwidth, rheight = rect 359 rx, ry, rwidth, rheight = rect
334 for event in graph.get_selected_regions(rx, ry, rwidth, rheight): 360 i_regs = graph.get_intersecting_regions(rx, ry, rwidth, rheight)
335 if event.get_layer() in was_selected and event in was_selected[event.get_layer()]: 361 for layer in i_regs:
336 self._select_event(remove_selected, event) 362 for event in i_regs[layer]:
363 if event.get_layer() in was_selected and event in was_selected[event.get_layer()]:
364 self._select_event(remove_selected, event)
337 365
338 add_reg = gtk.gdk.region_rectangle(gtk.gdk.Rectangle(x_p, y_p, width_p, height_p)) 366 add_reg = gtk.gdk.region_rectangle(gtk.gdk.Rectangle(x_p, y_p, width_p, height_p))
339 add_reg.subtract(old_reg) 367 add_reg.subtract(old_reg)
@@ -344,8 +372,10 @@ class GraphArea(gtk.DrawingArea):
344 graph.render_surface(self.renderer.get_schedule(), dirty_list, True) 372 graph.render_surface(self.renderer.get_schedule(), dirty_list, True)
345 for rect in dirty_list: 373 for rect in dirty_list:
346 rx, ry, rwidth, rheight = rect 374 rx, ry, rwidth, rheight = rect
347 for event in graph.get_selected_regions(rx, ry, rwidth, rheight): 375 i_regs = graph.get_intersecting_regions(rx, ry, rwidth, rheight)
348 self._select_event(add_selected, event) 376 for layer in i_regs:
377 for event in i_regs[layer]:
378 self._select_event(add_selected, event)
349 379
350 self.band_rect = x, y, width, height 380 self.band_rect = x, y, width, height
351 self.emit('request-refresh-events', self, add_selected, remove_selected, False) 381 self.emit('request-refresh-events', self, add_selected, remove_selected, False)
@@ -362,9 +392,9 @@ class GraphArea(gtk.DrawingArea):
362 self.left_button_start_coor = (button_event.x, button_event.y) 392 self.left_button_start_coor = (button_event.x, button_event.y)
363 graph.render_surface(self.renderer.get_schedule(), \ 393 graph.render_surface(self.renderer.get_schedule(), \
364 [(button_event.x, button_event.y, 0, 0)], True) 394 [(button_event.x, button_event.y, 0, 0)], True)
365 395
366 just_selected = graph.get_selected_regions(button_event.x, button_event.y, 0, 0) 396 just_selected = graph.get_intersecting_regions(button_event.x, button_event.y, 0, 0)
367 397
368 max_layer = self._find_max_layer(just_selected) 398 max_layer = self._find_max_layer(just_selected)
369 399
370 was_selected = self.renderer.get_schedule().get_selected() 400 was_selected = self.renderer.get_schedule().get_selected()
@@ -382,21 +412,21 @@ class GraphArea(gtk.DrawingArea):
382 # not intuitive to click something and then have something 412 # not intuitive to click something and then have something
383 # below it get selected). Also, clicking something that 413 # below it get selected). Also, clicking something that
384 # is selected deselects it, if it's the only thing selected 414 # is selected deselects it, if it's the only thing selected
385 for event in just_selected: 415 if just_selected:
386 if event.get_layer() == max_layer: 416 for event in just_selected[max_layer]:
387 if not (more_than_one == 1 and event in was_selected): 417 if not (more_than_one == 1 and max_layer in was_selected \
418 and event in was_selected[max_layer]):
388 self._select_event(new_now_selected, event) 419 self._select_event(new_now_selected, event)
389 break # only pick one event when just clicking 420 break # only pick one event when just clicking
390 421
391 self.emit('request-refresh-events', self, new_now_selected, was_selected, True) 422 self.emit('request-refresh-events', self, new_now_selected, was_selected, True)
392 else: 423 else:
393 remove_selected = {} 424 remove_selected = {}
394 add_selected = {} 425 add_selected = {}
395 426
396 for event in just_selected: 427 if just_selected:
397 layer = event.get_layer() 428 for event in just_selected[max_layer]:
398 if layer == max_layer: 429 if max_layer in was_selected and event in was_selected[max_layer]:
399 if layer in was_selected and event in was_selected[layer]:
400 self._select_event(remove_selected, event) 430 self._select_event(remove_selected, event)
401 else: 431 else:
402 self._select_event(add_selected, event) 432 self._select_event(add_selected, event)
@@ -566,40 +596,68 @@ class MainWindow(gtk.Window):
566 596
567 def __init__(self): 597 def __init__(self):
568 super(MainWindow, self).__init__(gtk.WINDOW_TOPLEVEL) 598 super(MainWindow, self).__init__(gtk.WINDOW_TOPLEVEL)
569 599
570 self.add_events(gtk.gdk.BUTTON_PRESS_MASK) 600 self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
571 601
572 self.connect('delete_event', self.delete_event) 602 self.connect('delete_event', self.delete_event)
573 self.connect('destroy', self.die) 603 self.connect('destroy', self.die)
574 604
575 file_menu = gtk.Menu() 605 file_menu = gtk.Menu()
606 edit_menu = gtk.Menu()
576 view_menu = gtk.Menu() 607 view_menu = gtk.Menu()
577 608
578 agr = gtk.AccelGroup() 609 agr = gtk.AccelGroup()
579 self.add_accel_group(agr) 610 self.add_accel_group(agr)
580 611
612 # list of file items that are clickable if and only if at
613 # least one graph is viewable
614 self.sensitive_menu_items = []
615
616 save_item = gtk.ImageMenuItem('_Save Graph to File')
617 img = gtk.Image()
618 img.set_from_stock(gtk.STOCK_SAVE_AS, gtk.ICON_SIZE_MENU)
619 save_item.set_image(img)
620 key, mod = gtk.accelerator_parse('<Ctrl>S')
621 save_item.add_accelerator('activate', agr, key, mod,
622 gtk.ACCEL_VISIBLE)
623 save_item.connect('activate', self.save_item_activate)
624 save_item.set_sensitive(False)
625 self.sensitive_menu_items.append(save_item)
626
581 quit_item = gtk.ImageMenuItem(gtk.STOCK_QUIT, agr) 627 quit_item = gtk.ImageMenuItem(gtk.STOCK_QUIT, agr)
582 key, mod = gtk.accelerator_parse('Q') 628 key, mod = gtk.accelerator_parse('<Ctrl>Q')
583 quit_item.add_accelerator('activate', agr, key, mod, 629 quit_item.add_accelerator('activate', agr, key, mod,
584 gtk.ACCEL_VISIBLE) 630 gtk.ACCEL_VISIBLE)
585 quit_item.connect('activate', self.quit_item_activate) 631 quit_item.connect('activate', self.quit_item_activate)
586 quit_item.show()
587 632
633 file_menu.append(save_item)
588 file_menu.append(quit_item) 634 file_menu.append(quit_item)
589 635
590 file_item = gtk.MenuItem('_File', True) 636 file_item = gtk.MenuItem('_File', True)
591 file_item.set_submenu(file_menu) 637 file_item.set_submenu(file_menu)
592 file_item.show()
593 638
594 self.move_item = gtk.ImageMenuItem('_Move to Time') 639 move_item = gtk.ImageMenuItem('_Move to Time')
595 key, mod = gtk.accelerator_parse('<Ctrl>M') 640 key, mod = gtk.accelerator_parse('<Ctrl>M')
596 self.move_item.add_accelerator('activate', agr, key, mod, 641 move_item.add_accelerator('activate', agr, key, mod,
597 gtk.ACCEL_VISIBLE) 642 gtk.ACCEL_VISIBLE)
598 self.move_item.set_sensitive(False) 643 move_item.set_sensitive(False)
599 644 self.sensitive_menu_items.append(move_item)
600 self.move_item.connect('activate', self.move_to_time_activate) 645
601 self.move_item.show() 646 move_item.connect('activate', self.move_to_time_activate)
602 647
648 self.colors_item = gtk.ImageMenuItem('Co_lors')
649 key, mod = gtk.accelerator_parse('<Ctrl>L')
650 self.colors_item.add_accelerator('activate', agr, key, mod,
651 gtk.ACCEL_VISIBLE)
652 self.colors_item.set_sensitive(False)
653
654 self.colors_item.connect('activate', self.colors_activate)
655
656 edit_menu.append(self.colors_item)
657
658 edit_item = gtk.MenuItem('_Edit', True)
659 edit_item.set_submenu(edit_menu)
660
603 zoom_in_item = gtk.ImageMenuItem(gtk.STOCK_ZOOM_IN, agr) 661 zoom_in_item = gtk.ImageMenuItem(gtk.STOCK_ZOOM_IN, agr)
604 key, mod = gtk.accelerator_parse('<Ctrl>plus') 662 key, mod = gtk.accelerator_parse('<Ctrl>plus')
605 zoom_in_item.add_accelerator('activate', agr, key, mod, 663 zoom_in_item.add_accelerator('activate', agr, key, mod,
@@ -608,7 +666,6 @@ class MainWindow(gtk.Window):
608 zoom_in_item.add_accelerator('activate', agr, key, mod, 0) 666 zoom_in_item.add_accelerator('activate', agr, key, mod, 0)
609 667
610 zoom_in_item.connect('activate', self.zoom_in_item_activate) 668 zoom_in_item.connect('activate', self.zoom_in_item_activate)
611 zoom_in_item.show()
612 669
613 zoom_out_item = gtk.ImageMenuItem(gtk.STOCK_ZOOM_OUT, agr) 670 zoom_out_item = gtk.ImageMenuItem(gtk.STOCK_ZOOM_OUT, agr)
614 key, mod = gtk.accelerator_parse('<Ctrl>minus') 671 key, mod = gtk.accelerator_parse('<Ctrl>minus')
@@ -618,21 +675,19 @@ class MainWindow(gtk.Window):
618 zoom_out_item.add_accelerator('activate', agr, key, mod, 0) 675 zoom_out_item.add_accelerator('activate', agr, key, mod, 0)
619 676
620 zoom_out_item.connect('activate', self.zoom_out_item_activate) 677 zoom_out_item.connect('activate', self.zoom_out_item_activate)
621 zoom_out_item.show()
622 678
623 view_menu.append(self.move_item) 679 view_menu.append(move_item)
624 view_menu.append(zoom_in_item) 680 view_menu.append(zoom_in_item)
625 view_menu.append(zoom_out_item) 681 view_menu.append(zoom_out_item)
626 682
627 view_item = gtk.MenuItem('_View', True) 683 view_item = gtk.MenuItem('_View', True)
628 view_item.set_submenu(view_menu) 684 view_item.set_submenu(view_menu)
629 view_item.show()
630 685
631 menu_bar = gtk.MenuBar() 686 menu_bar = gtk.MenuBar()
632 menu_bar.append(file_item) 687 menu_bar.append(file_item)
688 menu_bar.append(edit_item)
633 menu_bar.append(view_item) 689 menu_bar.append(view_item)
634 690
635 menu_bar.show()
636 self.vbox = gtk.VBox(False, 0) 691 self.vbox = gtk.VBox(False, 0)
637 692
638 self.notebook = gtk.Notebook() 693 self.notebook = gtk.Notebook()
@@ -640,25 +695,24 @@ class MainWindow(gtk.Window):
640 self.notebook.last_page = -1 695 self.notebook.last_page = -1
641 self.notebook.connect('switch-page', self.switch_page) 696 self.notebook.connect('switch-page', self.switch_page)
642 697
643 self.notebook.show()
644
645 self.desc_label = gtk.Label('') 698 self.desc_label = gtk.Label('')
646 self.desc_label.set_alignment(0.0, 0.0) 699 self.desc_label.set_alignment(0.0, 0.0)
647 self.desc_label.show()
648 700
649 self.vbox.pack_start(menu_bar, False, False, 0) 701 self.vbox.pack_start(menu_bar, False, False, 0)
650 self.vbox.pack_start(self.notebook, True, True, 0) 702 self.vbox.pack_start(self.notebook, True, True, 0)
651 self.vbox.pack_start(self.desc_label, False, False, 0) 703 self.vbox.pack_start(self.desc_label, False, False, 0)
652 self.vbox.show()
653 704
654 self.add(self.vbox) 705 self.add(self.vbox)
655 706
656 self.info_win = InfoWindow() 707 self.info_win = InfoWindow()
657 708 self.color_dialog = gtk.ColorSelectionDialog('Choose Item Color')
709
710 self.cur_item_no = None
711
658 self.set_size_request(MainWindow.WINDOW_WIDTH_REQ, MainWindow.WINDOW_HEIGHT_REQ) 712 self.set_size_request(MainWindow.WINDOW_WIDTH_REQ, MainWindow.WINDOW_HEIGHT_REQ)
659 713
660 self.set_title('Unit-Trace Visualizer') 714 self.set_title('Unit-Trace Visualizer')
661 self.show() 715 self.show_all()
662 716
663 def connect_widgets(self, gwindow): 717 def connect_widgets(self, gwindow):
664 gwindow.get_graph_area().connect('update-event-description', self.update_event_description) 718 gwindow.get_graph_area().connect('update-event-description', self.update_event_description)
@@ -666,6 +720,7 @@ class MainWindow(gtk.Window):
666 gwindow.get_graph_area().connect('request-refresh-events', self.request_refresh_events) 720 gwindow.get_graph_area().connect('request-refresh-events', self.request_refresh_events)
667 gwindow.connect('request-zoom-in', self.zoom_in_item_activate) 721 gwindow.connect('request-zoom-in', self.zoom_in_item_activate)
668 gwindow.connect('request-zoom-out', self.zoom_out_item_activate) 722 gwindow.connect('request-zoom-out', self.zoom_out_item_activate)
723 gwindow.get_graph_area().connect('update-sel-changes', self.update_sel_changes)
669 724
670 def set_renderers(self, renderers): 725 def set_renderers(self, renderers):
671 for i in range(0, self.notebook.get_n_pages()): 726 for i in range(0, self.notebook.get_n_pages()):
@@ -675,15 +730,28 @@ class MainWindow(gtk.Window):
675 self.connect_widgets(gwindow) 730 self.connect_widgets(gwindow)
676 gwindow.show() 731 gwindow.show()
677 self.notebook.append_page(gwindow, gtk.Label(title)) 732 self.notebook.append_page(gwindow, gtk.Label(title))
733
678 if self.notebook.get_n_pages() > 0: 734 if self.notebook.get_n_pages() > 0:
679 self.notebook.get_nth_page(0).grab_focus() 735 self.notebook.get_nth_page(0).grab_focus()
680 736
681 if self.notebook.get_n_pages() > 0: 737 if self.notebook.get_n_pages() > 0:
682 self.move_item.set_sensitive(True) 738 for menu_item in self.sensitive_menu_items:
739 menu_item.set_sensitive(True)
683 else: 740 else:
684 self.move_item.set_sensitive(False) 741 for menu_item in self.sensitive_menu_items:
685 742 menu_item.set_sensitive(False)
686 743
744 def update_sel_changes(self, widget, selected):
745 """Modify the GUI appropriately to reflect a change in selection."""
746 self.selected = selected
747
748 self.cur_item_no = self.notebook.get_nth_page(self.notebook.last_page).get_graph_area() \
749 .get_graph().all_one_item_selected(selected)
750 if self.cur_item_no is not None:
751 self.colors_item.set_sensitive(True)
752 else:
753 self.colors_item.set_sensitive(False)
754
687 def switch_page(self, widget, page, page_num): 755 def switch_page(self, widget, page, page_num):
688 if self.notebook.get_nth_page(self.notebook.last_page) is not None: 756 if self.notebook.get_nth_page(self.notebook.last_page) is not None:
689 old_value = self.notebook.get_nth_page(self.notebook.last_page).get_hadjustment().get_value() 757 old_value = self.notebook.get_nth_page(self.notebook.last_page).get_hadjustment().get_value()
@@ -710,11 +778,12 @@ class MainWindow(gtk.Window):
710 for i in range(0, self.notebook.get_n_pages()): 778 for i in range(0, self.notebook.get_n_pages()):
711 if self.notebook.get_nth_page(i).get_graph_area() is not sender: 779 if self.notebook.get_nth_page(i).get_graph_area() is not sender:
712 self.notebook.get_nth_page(i).get_graph_area().refresh_events(sender, old, new, replace) 780 self.notebook.get_nth_page(i).get_graph_area().refresh_events(sender, old, new, replace)
713 break
714 for i in range(0, self.notebook.get_n_pages()): 781 for i in range(0, self.notebook.get_n_pages()):
782 self.notebook.get_nth_page(i).get_graph_area().renderer.graph
715 if self.notebook.get_nth_page(i).get_graph_area() is sender: 783 if self.notebook.get_nth_page(i).get_graph_area() is sender:
716 self.notebook.get_nth_page(i).get_graph_area().refresh_events(sender, old, new, replace) 784 self.notebook.get_nth_page(i).get_graph_area().refresh_events(sender, old, new, replace)
717 785 break
786
718 def move_to_time_activate(self, widget): 787 def move_to_time_activate(self, widget):
719 dialog = TextInputDialog('Move to Time', 'What time to move to?', self) 788 dialog = TextInputDialog('Move to Time', 'What time to move to?', self)
720 789
@@ -760,6 +829,93 @@ class MainWindow(gtk.Window):
760 for i in range(0, self.notebook.get_n_pages()): 829 for i in range(0, self.notebook.get_n_pages()):
761 self.notebook.get_nth_page(i).get_graph_area().zoom_out() 830 self.notebook.get_nth_page(i).get_graph_area().zoom_out()
762 831
832 def colors_activate(self, widget):
833 garea = self.notebook.get_nth_page(self.notebook.last_page).get_graph_area()
834 graph = garea.get_renderer().get_graph()
835
836
837 pattern = graph.get_bar_pattern(self.cur_item_no)
838
839 if len(pattern.get_color_list()) > 1:
840 print 'striped patterns not yet supported'
841
842 r, g, b = pattern.get_color_list()[0]
843 colorsel = self.color_dialog.get_color_selection()
844 cur_color = gtk.gdk.Color(int(r * 65535), int(g * 65535), int(b * 65535))
845 colorsel.set_previous_color(cur_color)
846 colorsel.set_current_color(cur_color)
847 colorsel.set_has_palette(True)
848
849 if self.color_dialog.run() == gtk.RESPONSE_OK:
850 color = colorsel.get_current_color()
851 r, g, b = color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0
852 graph.set_bar_pattern(self.cur_item_no, Pattern([(r, g, b)]))
853 garea.refresh_all()
854
855 self.color_dialog.hide()
856
857 def save_item_activate(self, widget):
858 ACCEPTED_TYPES = ('png', 'svg')
859
860 dialog = gtk.FileChooserDialog('Save to Graphics File', self,
861 gtk.FILE_CHOOSER_ACTION_SAVE,
862 (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
863 gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT))
864
865 png_filter = gtk.FileFilter()
866 png_filter.add_mime_type('image/png')
867 png_filter.set_name('PNG image (*.png)')
868 dialog.add_filter(png_filter)
869
870 svg_filter = gtk.FileFilter()
871 svg_filter.add_mime_type('image/svg+xml')
872 svg_filter.set_name('SVG vector image (*.svg)')
873 dialog.add_filter(svg_filter)
874
875 filename = None
876 ftype = None
877 while True:
878 if dialog.run() == gtk.RESPONSE_ACCEPT:
879 filename = dialog.get_filename()
880 # parse filename for extension
881
882 parts = filename.split('.')
883 ftype = None
884 if len(parts) == 1:
885 filename += '.' + parts[0]
886 if dialog.get_filter() is png_filter:
887 ftype = 'png'
888 elif dialog.get_filter() is svg_filter:
889 ftype = 'svg'
890 break
891 else:
892 ftype = parts[-1]
893 if ftype in ACCEPTED_TYPES:
894 break
895 else:
896 err_dialog = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT,
897 gtk.MESSAGE_ERROR,
898 gtk.BUTTONS_CLOSE,
899 'File type "' + ftype + '" not recognized')
900 err_dialog.set_title('File Type Error')
901 err_dialog.run()
902 err_dialog.destroy()
903 else:
904 filename = None
905 ftype = None
906 break
907
908 if filename is not None:
909 cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
910 dialog.get_window().set_cursor(cursor)
911 def idle_callback(dialog):
912 self.notebook.get_nth_page(self.notebook.last_page).get_graph_area().output_to_file(filename, ftype)
913 dialog.get_window().set_cursor(None)
914 dialog.destroy()
915 gobject.idle_add(idle_callback, dialog) # needed to get the cursor to display
916 else:
917 dialog.destroy()
918
763 def quit_item_activate(self, widget): 919 def quit_item_activate(self, widget):
764 self.destroy() 920 self.destroy()
765 921