12 def __init__(self, start = 0, end = 0, value = ''):
29 diff = a.start - b.start
54 if key >= self.
ranges[i].start
and key <= self.
ranges[i].end:
56 elif key < self.
ranges[i].start:
63 self.ranges.append(range)
69 if s == -1
and e == -1:
72 return self.
ranges[0:e + 1]
76 return self.
ranges[s:e + 1]
80 if s == -1
and e == -1:
85 return(s, len(self.
ranges))
89 self.ranges.sort(ranges_cmp)
106 if key == self.
events[i].at:
108 elif key < self.
events[i].at:
115 self.events.append(event)
119 return self.
events[s:e + 1]
125 self.events.sort(events_cmp)
142 if range.name == name:
145 self.ranges.append(timeline)
149 if event_str.name == name:
152 self.event_str.append(timeline)
156 if event_int.name == name:
159 self.event_int.append(timeline)
178 (range_lo, range_hi) = range.get_bounds()
184 (ev_lo, ev_hi) = event_str.get_bounds()
190 (ev_lo, ev_hi) = event_int.get_bounds()
201 if timeline.name == name:
204 self.timelines.append(timeline)
215 (t_lo, t_hi) = timeline.get_bounds()
224 for ranges
in timeline.get_ranges():
225 for ran
in ranges.get_all():
226 range_values[ran.value] = 1
227 return range_values.keys()
239 default_colors = [
Color(1, 0, 0),
Color(0, 1, 0),
Color(0, 0, 1),
Color(1, 1, 0),
Color(1, 0, 1),
Color(0, 1, 1)]
242 def add(self, name, color):
245 if not self.__colors.has_key(name):
246 self.
add(name, self.default_colors.pop())
247 return self.__colors.get(name)
260 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1)
261 ctx = cairo.Context(surface)
266 (t_width, t_height) = ctx.text_extents(legend)[2:4]
269 if item_height > line_height:
270 line_height = item_height
271 if line_used + item_width > self.
__width:
273 total_height += line_height
275 line_used += item_width
276 x = line_used - item_width
277 total_height += line_height
288 (t_width, t_height) = ctx.text_extents(legend)[2:4]
291 if item_height > line_height:
292 line_height = item_height
293 if line_used + item_width > self.
__width:
295 total_height += line_height
297 line_used += item_width
298 x = line_used - item_width
300 ctx.set_source_rgb(0, 0, 0)
301 ctx.set_line_width(2)
302 ctx.stroke_preserve()
303 ctx.set_source_rgb(self.
__colors[i].r,
307 ctx.move_to(x + self.
__padding*2, total_height + t_height)
308 ctx.set_source_rgb(0, 0, 0)
309 ctx.show_text(legend)
329 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1)
330 ctx = cairo.Context(surface)
331 max_text_height = ctx.text_extents(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789")[3]
339 for timeline
in self.timelines.get_all():
341 t_width = ctx.text_extents(timeline.name)[2]
342 left_width = max(left_width, t_width)
343 for rang
in timeline.get_ranges():
344 t_width = ctx.text_extents(rang.name)[2]
345 right_width = max(right_width, t_width)
347 for events_int
in timeline.get_events_int():
348 t_width = ctx.text_extents(events_int.name)[2]
349 right_width = max(right_width, t_width)
351 for events_str
in timeline.get_events_str():
352 t_width = ctx.text_extents(events_str.name)[2]
353 right_width = max(right_width, t_width)
356 left_height = left_n_lines * max_text_height + (left_n_lines - 1) * self.
padding
357 right_n_lines = range_n + eventint_n + eventstr_n
358 right_height = (right_n_lines - 1) * self.
padding + right_n_lines * max_text_height
359 right_data_height = (eventint_n + eventstr_n) * (max_text_height + 5) + range_n * 10
360 right_data_height += (right_n_lines - 1) * self.
padding
362 height = max(left_height, right_height)
363 height = max(height, right_data_height)
372 ctx.rel_line_to(width, height)
374 ctx.set_operator(cairo.OPERATOR_SOURCE)
375 ctx.set_line_width(1.0)
376 ctx.set_source_rgb(0, 0, 0)
380 ctx.rectangle(x, y - self.
padding / 2,
382 ctx.set_source_rgb(0.9, 0.9, 0.9)
384 last_x_drawn = int(x)
385 (lo, hi) = events.get_events_bounds(self.
start, self.
end)
386 for event
in events.events[lo:hi]:
387 real_x = int(x + (event.at - self.
start) * width / (self.
end - self.
start))
388 if real_x > last_x_drawn + 2:
389 ctx.rectangle(real_x, y, 1, 1)
390 ctx.set_source_rgb(1, 0, 0)
393 ctx.set_source_rgb(0, 0, 0)
394 ctx.show_text(str(event.value))
395 last_x_drawn = real_x
399 ctx.rectangle(x, y - self.
padding / 2,
401 ctx.set_source_rgb(0.9, 0.9, 0.9)
403 last_x_drawn = int(x - 1)
404 (lo, hi) = ranges.get_ranges_bounds(self.
start, self.
end)
405 for data_range
in ranges.ranges[lo:hi]:
406 s = max(data_range.start, self.
start)
407 e = min(data_range.end, self.
end)
408 x_start = int(x + (s - self.
start) * width / (self.
end - self.
start))
409 x_end = int(x + (e - self.
start) * width / (self.
end - self.
start))
410 if x_end > last_x_drawn:
411 ctx.rectangle(x_start, y, x_end - x_start, 10)
412 ctx.set_source_rgb(0, 0, 0)
413 ctx.stroke_preserve()
414 color = self.colors.lookup(data_range.value)
415 ctx.set_source_rgb(color.r, color.g, color.b)
424 left_x_start = self.
padding / 2
426 right_x_start = left_x_end + self.
padding
428 data_x_start = right_x_end + self.
padding / 2
429 data_x_end = self.
width
430 data_width = data_x_end - data_x_start
434 for timeline
in self.timelines.get_all():
435 (y_bearing, t_width, t_height) = ctx.text_extents(timeline.name)[1:4]
436 ctx.move_to(left_x_start, cur_y + self.
max_text_height - (t_height + y_bearing))
437 ctx.show_text(timeline.name);
438 for events_int
in timeline.get_events_int():
439 (y_bearing, t_width, t_height) = ctx.text_extents(events_int.name)[1:4]
440 ctx.move_to(right_x_start, cur_y + self.
max_text_height - (t_height + y_bearing))
441 ctx.show_text(events_int.name)
447 for events_str
in timeline.get_events_str():
448 (y_bearing, t_width, t_height) = ctx.text_extents(events_str.name)[1:4]
449 ctx.move_to(right_x_start, cur_y + self.
max_text_height - (t_height + y_bearing))
450 ctx.show_text(events_str.name)
455 for ranges
in timeline.get_ranges():
456 (y_bearing, t_width, t_height) = ctx.text_extents(ranges.name)[1:4]
457 ctx.move_to(right_x_start, cur_y + self.
max_text_height - (t_height + y_bearing))
458 ctx.show_text(ranges.name)
459 self.
draw_ranges(ctx, ranges, data_x_start, cur_y, data_width, 10)
465 bot_y = cur_y - self.
padding / 2
487 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1)
488 ctx = cairo.Context(surface)
493 while (closest*10) < data_delta:
495 if (data_delta / closest) == 0:
497 elif(data_delta / closest) == 1:
501 start = self.
__lo - (self.
__lo % delta) + delta
502 end = self.
__hi - (self.
__hi % delta)
508 max_text_height = ctx.text_extents(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789")[3]
510 height = max_text_height + 10
517 start = self.
__lo - (self.
__lo % delta) + delta
518 end = self.
__hi - (self.
__hi % delta)
525 ctx.set_source_rgb(0, 0, 0)
526 ctx.set_line_width(1.0)
527 ticks = range(int(start), int(end + delta), int(delta))
530 ctx.move_to(real_x, 0)
531 ctx.line_to(real_x, 5*s)
534 (t_y_bearing, t_width, t_height) = ctx.text_extents(str(x))[1:4]
536 text_delta = t_height + t_y_bearing
538 text_delta = -t_y_bearing
539 ctx.move_to(real_x - t_width / 2, (5 + 5 + text_delta)*s)
540 ctx.show_text(str(x))
544 start = self.
__lo - (self.
__lo % delta) + delta
545 end = self.
__hi - (self.
__hi % delta)
546 for x
in range(int(start), int(end + delta), int(delta)):
548 ctx.move_to(real_x, 0)
549 ctx.line_to(real_x, 3*s)
560 self.__mid_scale.set_top()
562 self.__bot_scale.set_bounds(start, end)
563 self.__bot_scale.set_bot()
572 y_start = self.__top_legend.get_height()
573 x_start = self.__data.get_data_x_start()
574 return(x_start, y_start, self.
__width - x_start, self.__data.get_height())
576 x_start = self.__data.get_data_x_start()
581 y_start = self.__top_legend.get_height() + self.__data.get_height() + self.__mid_scale.get_height() + 20
582 y_height = self.__bot_scale.get_height() + 20
583 x_start = self.__bot_scale.get_position(self.
__r_start)
584 x_end = self.__bot_scale.get_position(self.
__r_end)
585 return(x_start, y_start, x_end - x_start, y_height)
593 end = min(self.
__end, e)
596 self.__data.set_render_range(start, end)
597 self.__mid_scale.set_bounds(start, end)
608 self.__top_legend.layout(width)
609 top_legend_height = self.__top_legend.get_height()
610 self.__data.layout(width)
611 self.__mid_scale.layout(width - self.__data.get_data_x_start())
612 self.__bot_scale.layout(width)
621 ctx.set_source_rgb(1, 1, 1)
622 ctx.set_operator(cairo.OPERATOR_SOURCE)
628 self.__top_legend.draw(ctx)
629 top_legend_height = self.__top_legend.get_height()
633 ctx.move_to(0, top_legend_height)
634 ctx.line_to(self.
__width, top_legend_height)
636 ctx.set_line_width(2)
637 ctx.set_source_rgb(0, 0, 0)
644 self.__data.draw(ctx)
649 ctx.translate(self.__data.get_data_x_start(),
650 top_legend_height + self.__data.get_height() + self.__mid_scale.get_height())
651 self.__mid_scale.draw(ctx)
654 height_used = top_legend_height + self.__data.get_height() + self.__mid_scale.get_height()
657 ctx.move_to(self.__data.get_data_x_start(), height_used)
658 ctx.rel_line_to(0, -self.__mid_scale.get_height())
660 ctx.set_source_rgb(0, 0, 0)
661 ctx.set_line_width(2)
665 ctx.move_to(0, height_used)
666 ctx.line_to(self.
__width, height_used)
668 ctx.set_line_width(2)
669 ctx.set_source_rgb(0, 0, 0)
672 select_start = self.__bot_scale.get_position(self.
__r_start)
673 select_end = self.__bot_scale.get_position(self.
__r_end)
676 ctx.move_to(0, height_used);
677 ctx.line_to(self.__data.get_data_x_start(), height_used)
678 ctx.line_to(select_start, height_used + 20)
679 ctx.line_to(0, height_used + 20)
680 ctx.line_to(0, height_used)
681 ctx.set_source_rgb(0, 0, 0)
682 ctx.set_line_width(1)
683 ctx.stroke_preserve()
684 ctx.set_source_rgb(0.9, 0.9, 0.9)
688 ctx.move_to(self.
__width, height_used)
689 ctx.line_to(self.
__width, height_used + 20)
690 ctx.line_to(select_end, height_used + 20)
691 ctx.line_to(self.
__width, height_used)
692 ctx.set_source_rgb(0, 0, 0)
693 ctx.set_line_width(1)
694 ctx.stroke_preserve()
695 ctx.set_source_rgb(0.9, 0.9, 0.9)
701 unused_start = self.__bot_scale.get_position(self.
__r_start)
702 unused_end = self.__bot_scale.get_position(self.
__r_end)
703 unused_height = self.__bot_scale.get_height() + 20
704 ctx.rectangle(0, height_used,
707 ctx.rectangle(unused_end,
711 ctx.set_source_rgb(0.9, 0.9, 0.9)
715 ctx.move_to(unused_end, height_used)
716 ctx.line_to(self.
__width, height_used)
717 ctx.line_to(self.
__width, height_used + unused_height)
718 ctx.line_to(0, height_used + unused_height)
719 ctx.line_to(0, height_used)
720 ctx.line_to(unused_start, height_used)
722 ctx.set_line_width(2)
723 ctx.set_source_rgb(0, 0, 0)
725 ctx.move_to(unused_start, height_used)
726 ctx.line_to(unused_end, height_used)
728 ctx.set_line_width(1)
729 ctx.set_source_rgb(0.9, 0.9, 0.9)
734 ctx.move_to(max(unused_start, 2), height_used)
735 ctx.rel_line_to(0, unused_height)
736 ctx.move_to(min(unused_end, self.
__width - 2), height_used)
737 ctx.rel_line_to(0, unused_height)
739 ctx.set_source_rgb(0, 0, 0)
740 ctx.set_line_width(1)
746 ctx.translate(0, height_used)
747 self.__bot_scale.draw(ctx)
752 super(GtkGraphicRenderer, self).
__init__()
759 self.add_events(gtk.gdk.POINTER_MOTION_MASK)
760 self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
761 self.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
762 self.connect(
"expose_event", self.
expose)
768 (start, end) = self.__data.get_range()
769 self.__data.set_range(start, start + (end - start)*2)
773 (start, end) = self.__data.get_range()
774 self.__data.set_range(start, start + (end - start) / 2)
778 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
779 self.__data.get_width(),
780 self.__data.get_height())
782 self.__data.draw(ctx)
783 surface.write_to_png(filename)
785 (x, y, width, height) = self.__data.get_selection_rectangle()
786 (d_x, d_y, d_width, d_height) = self.__data.get_data_rectangle()
787 if event.y > y
and event.y < y + height:
788 if abs(event.x - x) < 5:
791 if abs(event.x - (x + width)) < 5:
794 if event.x > x
and event.x < x + width:
799 if event.y > d_y
and event.y < (d_y + d_height):
800 if event.x > d_x
and event.x < (d_x + d_width):
810 right = self.__data.get_range()[1]
811 self.__data.set_range(left, right)
818 left = self.__data.get_range()[0]
819 self.__data.set_range(left, right)
826 (left, right) = self.__data.get_range()
827 self.__data.set_range(left + delta, right + delta)
835 (x, y, width, height) = self.__data.get_selection_rectangle()
839 elif event.x >= x + width:
843 self.queue_draw_area(0, int(y), int(self.
__width), int(height))
852 self.queue_draw_area(0, int(y), int(self.
__width), int(height))
859 elif event.x > cur_e:
863 self.queue_draw_area(0, int(y), int(self.
__width), int(height))
868 (left, right) = self.__data.get_range()
869 self.__data.set_range(left + delta, right + delta)
874 (d_x, d_y, d_width, d_height) = self.__data.get_data_rectangle()
875 if event.y > y
and event.y < y + height:
876 if abs(event.x - x) < 5
or abs(event.x - (x + width)) < 5:
877 widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.SB_H_DOUBLE_ARROW))
879 if event.x > x
and event.x < x + width:
880 widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
882 if event.y > d_y
and event.y < (d_y + d_height):
883 if event.x > d_x
and event.x < (d_x + d_width):
884 widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
886 widget.window.set_cursor(
None)
891 self.__data.layout(allocation.width, allocation.height)
897 self.__data.get_width(),
898 self.__data.get_height())
900 self.__data.draw(ctx)
902 ctx = widget.window.cairo_create()
903 ctx.rectangle(event.area.x, event.area.y,
904 event.area.width, event.area.height)
908 (x, y, width, height) = self.__data.get_selection_rectangle()
911 ctx.rel_line_to(0, height)
913 ctx.set_line_width(1)
914 ctx.set_source_rgb(0, 0, 0)
918 ctx.rel_line_to(0, height)
920 ctx.set_line_width(1)
921 ctx.set_source_rgb(0, 0, 0)
926 ctx.move_to(x + delta_x, y)
927 ctx.rel_line_to(0, height)
929 ctx.move_to(x + width + delta_x, y)
930 ctx.rel_line_to(0, height)
932 ctx.set_source_rgb(0, 0, 0)
933 ctx.set_line_width(1)
941 window = gtk.Window()
943 window.set_default_size(200, 200)
948 vbox.pack_end(render,
True,
True, 0)
950 vbox.pack_start(hbox,
False,
False, 0)
951 smaller_zoom = gtk.Button(
"Zoom Out")
953 hbox.pack_start(smaller_zoom)
954 bigger_zoom = gtk.Button(
"Zoom In")
956 hbox.pack_start(bigger_zoom)
957 output_png = gtk.Button(
"Output Png")
959 hbox.pack_start(output_png)
960 window.connect(
'destroy', gtk.main_quit)
965 self.__render.set_smaller_zoom()
967 self.__render.set_bigger_zoom()
969 dialog = gtk.FileChooserDialog(
"Output Png", self.
__window,
970 gtk.FILE_CHOOSER_ACTION_SAVE, (
"Save", 1))
972 dialog.set_default_response(1)
978 filename = self.__dialog.get_filename()
979 self.__render.output_png(filename)
989 m1 = re.compile(
'range ([^ ]+) ([^ ]+) ([^ ]+) ([0-9]+) ([0-9]+)')
990 m2 = re.compile(
'event-str ([^ ]+) ([^ ]+) ([^ ]+) ([0-9]+)')
991 m3 = re.compile(
'event-int ([^ ]+) ([^ ]+) ([0-9]+) ([0-9]+)')
992 m4 = re.compile(
'color ([^ ]+) #([a-fA-F0-9]{2,2})([a-fA-F0-9]{2,2})([a-fA-F0-9]{2,2})')
993 for line
in fh.readlines():
996 line_name = m.group(1)
997 timeline = timelines.get(m.group(1))
998 rang = timeline.get_range(m.group(2))
1000 data_range.value = m.group(3)
1001 data_range.start = int(m.group(4))
1002 data_range.end = int(m.group(5))
1003 rang.add_range(data_range)
1007 line_name = m.group(1)
1008 timeline = timelines.get(m.group(1))
1009 ev = timeline.get_event_str(m.group(2))
1011 event.value = m.group(3)
1012 event.at = int(m.group(4))
1017 line_name = m.group(1)
1018 timeline = timelines.get(m.group(1))
1019 ev = timeline.get_event_int(m.group(2))
1021 event.value = int(m.group(3))
1022 event.at = int(m.group(4))
1028 r = int(m.group(2), 16)
1029 g = int(m.group(3), 16)
1030 b = int(m.group(4), 16)
1031 color =
Color(r / 255, g / 255, b / 255)
1032 colors.add(m.group(1), color)
1035 return (colors, timelines)
1040 (colors, timelines) =
read_data(sys.argv[1])
1041 (lower_bound, upper_bound) = timelines.get_bounds()
1044 range_values = timelines.get_all_range_values()
1046 for range_value
in range_values:
1047 range_colors.append(colors.lookup(range_value))
1048 top_legend.set_legends(range_values,
1050 graphic.set_top_legend(top_legend)
1052 data.set_timelines(timelines, colors)
1053 graphic.set_data(data)
1056 range_mid = (upper_bound - lower_bound) / 2
1057 range_width = (upper_bound - lower_bound) / 10
1058 range_lo = range_mid - range_width / 2
1059 range_hi = range_mid + range_width / 2
1060 graphic.set_range(range_lo, range_hi)
1063 main_window.run(graphic)
def get_ranges(self, start, end)
def expose(self, widget, event)
def set_bounds(self, lo, hi)
def draw_events(self, ctx, events, x, y, width, height)
def set_range(self, start, end)
def get_data_x_start(self)
def set_top_legend(self, top_legend)
def set_render_range(self, start, end)
def get_ranges_bounds(self, start, end)
def __x_pixel(self, x, width)
def add_range(self, range)
def set_legends(self, legends, colors)
def scale_selection(self, x)
def set_smaller_zoom(self)
def get_data_rectangle(self)
def __dialog_response_cb(self, widget, response)
def get_all_range_values(self)
def draw_ranges(self, ctx, ranges, x, y, width, height)
def get_event_int(self, name)
def add(self, name, color)
def __init__(self, start, end)
def __output_png_cb(self, widget)
def get_events(self, start, end)
def button_press(self, widget, event)
def set_timelines(self, timelines, colors)
def get_events_bounds(self, start, end)
def motion_notify(self, widget, event)
def __set_smaller_cb(self, widget)
def set_padding(self, padding)
def output_png(self, filename)
def button_release(self, widget, event)
def set_bigger_zoom(self)
def add_event(self, event)
def get_event_str(self, name)
def layout(self, width, height)
def draw_line(self, ctx, x, y, width, height)
def get_selection_rectangle(self)
def size_allocate(self, widget, allocation)
def get_range(self, name)
def get_position(self, x)
def __set_bigger_cb(self, widget)