A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
grid.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3import re
4import sys
5
6import cairo
7import gtk
8
9
10## DataRange class
12 ## @var start
13 # start
14 ## @var end
15 # end
16 ## @var value
17 # value
18 def __init__(self, start=0, end=0, value=""):
19 """! Initializer
20 @param self this object
21 @param start start
22 @param end end
23 @param value value
24 """
25 self.start = start
26 self.end = end
27 self.value = value
28
29
30## EventString class
32 ## @var at
33 # at
34 ## @var value
35 # value
36 def __init__(self, at=0, value=""):
37 """! Initializer
38 @param self this object
39 @param at you
40 @param value value
41 """
42 self.at = at
43 self.value = value
44
45
46## EventFloat class
48 ## @var at
49 # at
50 ## @var value
51 # value
52 def __init__(self, at=0, value=0.0):
53 """! Initializer
54 @param self this object
55 @param at you
56 @param value value
57 """
58 self.at = at
59 self.value = value
60
61
62## EventInt class
64 ## @var at
65 # at
66 ## @var value
67 # value
68 def __init__(self, at=0, value=0.0):
69 """! Initializer
70 @param self this object
71 @param at you
72 @param value value
73 """
74 self.at = at
75 self.value = value
76
77
78def ranges_cmp(a, b):
79 diff = a.start - b.start
80 if diff < 0:
81 return -1
82 elif diff > 0:
83 return +1
84 else:
85 return 0
86
87
88def events_cmp(a, b):
89 diff = a.at - b.at
90 if diff < 0:
91 return -1
92 elif diff > 0:
93 return +1
94 else:
95 return 0
96
97
98## TimelineDataRange
100 ## @var name
101 # name
102 ## @var ranges
103 # ranges
104 def __init__(self, name=""):
105 """! Initializer
106 @param self this object
107 @param name name
108 """
109 self.name = name
110 self.ranges = []
111 return
112
113 def __search(self, key):
114 """! Search
115 @param self this object
116 @param key key
117 @return index if found or -1 if not found
118 """
119 l = 0
120 u = len(self.ranges) - 1
121 while l <= u:
122 i = int((l + u) / 2)
123 if key >= self.ranges[i].start and key <= self.ranges[i].end:
124 return i
125 elif key < self.ranges[i].start:
126 u = i - 1
127 else:
128 # key > self.ranges[i].end
129 l = i + 1
130 return -1
131
132 def add_range(self, range):
133 """! Add range
134 @param self this object
135 @param range range
136 @return none
137 """
138 self.ranges.append(range)
139
140 def get_all(self):
141 """! Get all ranges
142 @param self this object
143 @return the ranges
144 """
145 return self.ranges
146
147 def get_ranges(self, start, end):
148 """! Get selected ranges
149 @param self this object
150 @param start range start
151 @param end range end
152 @return the range or and empty list
153 """
154 s = self.__search(start)
155 e = self.__search(end)
156 if s == -1 and e == -1:
157 return []
158 elif s == -1:
159 return self.ranges[0 : e + 1]
160 elif e == -1:
161 return self.ranges[s : len(self.ranges)]
162 else:
163 return self.ranges[s : e + 1]
164
165 def get_ranges_bounds(self, start, end):
166 """! Get ranges bounds
167 @param self this object
168 @param start range start
169 @param end range end
170 @return range
171 """
172 s = self.__search(start)
173 e = self.__search(end)
174 if s == -1 and e == -1:
175 return (0, 0)
176 elif s == -1:
177 return (0, e + 1)
178 elif e == -1:
179 return (s, len(self.ranges))
180 else:
181 return (s, e + 1)
182
183 def sort(self):
184 """! Sort ranges
185 @param self this object
186 @return none
187 """
188 self.ranges.sort(ranges_cmp)
189
190 def get_bounds(self):
191 """! Get bounds
192 @param self this object
193 @return the bounds
194 """
195 if len(self.ranges) > 0:
196 lo = self.ranges[0].start
197 hi = self.ranges[len(self.ranges) - 1].end
198 return (lo, hi)
199 else:
200 return (0, 0)
201
202
203## TimelineEvent class
205 ## @var name
206 # name
207 ## @var events
208 # events
209 def __init__(self, name=""):
210 """! Get ranges bounds
211 @param self this object
212 @param name name
213 """
214 self.name = name
215 self.events = []
216
217 def __search(self, key):
218 """! Search function
219 @param self this object
220 @param key the key
221 @return event index
222 """
223 l = 0
224 u = len(self.events) - 1
225 while l <= u:
226 i = int((l + u) / 2)
227 if key == self.events[i].at:
228 return i
229 elif key < self.events[i].at:
230 u = i - 1
231 else:
232 # key > self.events[i].at
233 l = i + 1
234 return l
235
236 def add_event(self, event):
237 """! Add Event
238 @param self this object
239 @param event event to add
240 @return none
241 """
242 self.events.append(event)
243
244 def get_events(self, start, end):
245 """! Get Events
246 @param self this object
247 @param start starting event
248 @param end ending event
249 @return the events
250 """
251 s = self.__search(start)
252 e = self.__search(end)
253 return self.events[s : e + 1]
254
255 def get_events_bounds(self, start, end):
256 """! Get Events Bounds
257 @param self this object
258 @param start starting event
259 @param end ending event
260 @return event bounds
261 """
262 s = self.__search(start)
263 e = self.__search(end)
264 return (s, e + 1)
265
266 def sort(self):
267 """! Sort function
268 @param self this object
269 @return none
270 """
271 self.events.sort(events_cmp)
272
273 def get_bounds(self):
274 """! Get Bounds
275 @param self this object
276 @return the bounds
277 """
278 if len(self.events) > 0:
279 lo = self.events[0].at
280 hi = self.events[-1].at
281 return (lo, hi)
282 else:
283 return (0, 0)
284
285
286## Timeline class
288 ## @var name
289 # name
290 ## @var ranges
291 # ranges
292 ## @var event_str
293 # event string
294 ## @var event_int
295 # event int
296 def __init__(self, name=""):
297 """! Initializer
298 @param self this object
299 @param name name
300 """
301 self.ranges = []
302 self.event_str = []
303 self.event_int = []
304 self.name = name
305
306 def get_range(self, name):
307 """! Get range
308 @param self this object
309 @param name name
310 @return the range
311 """
312 for range in self.ranges:
313 if range.name == name:
314 return range
315 timeline = TimelineDataRange(name)
316 self.ranges.append(timeline)
317 return timeline
318
319 def get_event_str(self, name):
320 """! Get Event String
321 @param self this object
322 @param name name
323 @return the event string
324 """
325 for event_str in self.event_str:
326 if event_str.name == name:
327 return event_str
328 timeline = TimelineEvent(name)
329 self.event_str.append(timeline)
330 return timeline
331
332 def get_event_int(self, name):
333 """! Get Event Int
334 @param self this object
335 @param name name
336 @return eevent int
337 """
338 for event_int in self.event_int:
339 if event_int.name == name:
340 return event_int
341 timeline = TimelineEvent(name)
342 self.event_int.append(timeline)
343 return timeline
344
345 def get_ranges(self):
346 """! Get Ranges
347 @param self this object
348 @return the ranges
349 """
350 return self.ranges
351
352 def get_events_str(self):
353 """! Get Events string
354 @param self this object
355 @return event string
356 """
357 return self.event_str
358
359 def get_events_int(self):
360 """! Get Events int
361 @param self this object
362 @return evrnt int
363 """
364 return self.event_int
365
366 def sort(self):
367 """! Sort the ranges and events
368 @param self this object
369 @return none
370 """
371 for range in self.ranges:
372 range.sort()
373 for event in self.event_int:
374 event.sort()
375 for event in self.event_str:
376 event.sort()
377
378 def get_bounds(self):
379 """! Get Bounds
380 @param self this object
381 @return the bounds
382 """
383 lo = 0
384 hi = 0
385 for range in self.ranges:
386 (range_lo, range_hi) = range.get_bounds()
387 if range_lo < lo:
388 lo = range_lo
389 if range_hi > hi:
390 hi = range_hi
391 for event_str in self.event_str:
392 (ev_lo, ev_hi) = event_str.get_bounds()
393 if ev_lo < lo:
394 lo = ev_lo
395 if ev_hi > hi:
396 hi = ev_hi
397 for event_int in self.event_int:
398 (ev_lo, ev_hi) = event_int.get_bounds()
399 if ev_lo < lo:
400 lo = ev_lo
401 if ev_hi > hi:
402 hi = ev_hi
403 return (lo, hi)
404
405
406## Timelines class
408 ## @var timelines
409 # timelines
410 def __init__(self):
411 """Initializer
412 @param self: this object
413 """
414 self.timelines = []
415
416 def get(self, name):
417 """! Get Timeline
418 @param self this object
419 @param name name
420 @return the timeline for the name
421 """
422 for timeline in self.timelines:
423 if timeline.name == name:
424 return timeline
425 timeline = Timeline(name)
426 self.timelines.append(timeline)
427 return timeline
428
429 def get_all(self):
430 """! Get All Timeline
431 @param self this object
432 @return all timelines
433 """
434 return self.timelines
435
436 def sort(self):
437 """! Sort the timelines
438 @param self this object
439 @return none
440 """
441 for timeline in self.timelines:
442 timeline.sort()
443
444 def get_bounds(self):
445 """! Get Bounds
446 @param self this object
447 @return the bounds for all timelines
448 """
449 lo = 0
450 hi = 0
451 for timeline in self.timelines:
452 (t_lo, t_hi) = timeline.get_bounds()
453 if t_lo < lo:
454 lo = t_lo
455 if t_hi > hi:
456 hi = t_hi
457 return (lo, hi)
458
460 """! Get All Ranges
461 @param self this object
462 @return the keys for all ranges
463 """
464 range_values = {}
465 for timeline in self.timelines:
466 for ranges in timeline.get_ranges():
467 for ran in ranges.get_all():
468 range_values[ran.value] = 1
469 return range_values.keys()
470
471
472## Color class
473class Color:
474 ## @var r
475 # red
476 ## @var g
477 # green
478 ## @var b
479 # blue
480 def __init__(self, r=0.0, g=0.0, b=0.0):
481 """! Initializer
482 @param self: this object
483 @param r: red
484 @param g: green
485 @param b: blue
486 """
487 self.r = r
488 self.g = g
489 self.b = b
490
491 def set(self, r, g, b):
492 """! Set color
493 @param self: this object
494 @param r: red
495 @param g: green
496 @param b: blue
497 @return none
498 """
499 self.r = r
500 self.g = g
501 self.b = b
502
503
504## Colors class
505class Colors:
506 ## @var __colors
507 # colors
508 ## @var default_colors
509 # default colors
510 ## XXX add more
511 default_colors = [
512 Color(1, 0, 0),
513 Color(0, 1, 0),
514 Color(0, 0, 1),
515 Color(1, 1, 0),
516 Color(1, 0, 1),
517 Color(0, 1, 1),
518 ]
519
520 def __init__(self):
521 """! Initializer
522 @param self this object
523 """
524 self.__colors = {}
525
526 def add(self, name, color):
527 """! Add
528 @param self this object
529 @param name name of the color
530 @param color color value
531 @return none
532 """
533 self.__colors[name] = color
534
535 def lookup(self, name):
536 """! Lookup name
537 @param self this object
538 @param name name
539 @return named color
540 """
541 if not self.__colors.has_key(name):
542 self.add(name, self.default_colors.pop())
543 return self.__colors.get(name)
544
545
546## TopLegendRenderer class
548 ## @var __padding
549 # padding
550 ## @var __legends
551 # legends
552 ## @var __colors
553 # colors
554 ## @var __width
555 # width
556 ## @var __height
557 # height
558 def __init__(self):
559 """! Initializer
560 @param self this object
561 """
562 self.__padding = 10
563
564 def set_padding(self, padding):
565 """! Set padding
566 @param self this object
567 @param padding padding
568 @return none
569 """
570 self.__padding = padding
571
572 def set_legends(self, legends, colors):
573 """! Set padding
574 @param self this object
575 @param legends legends
576 @param colors colors
577 @return none
578 """
579 self.__legends = legends
580 self.__colors = colors
581
582 def layout(self, width):
583 """! Set padding
584 @param self this object
585 @param width width
586 @return none
587 """
588 self.__width = width
589 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1)
590 ctx = cairo.Context(surface)
591 line_height = 0
592 total_height = self.__padding
593 line_used = self.__padding
594 for legend in self.__legends:
595 (t_width, t_height) = ctx.text_extents(legend)[2:4]
596 item_width = self.__padding + self.__padding + t_width + self.__padding
597 item_height = t_height + self.__padding
598 if item_height > line_height:
599 line_height = item_height
600 if line_used + item_width > self.__width:
601 line_used = self.__padding + item_width
602 total_height += line_height
603 else:
604 line_used += item_width
605 x = line_used - item_width
606 total_height += line_height
607 self.__height = total_height
608
609 def get_height(self):
610 """! Set padding
611 @param self this object
612 @return height
613 """
614 return self.__height
615
616 def draw(self, ctx):
617 """! Set padding
618 @param self this object
619 @param ctx ctx
620 @return none
621 """
622 i = 0
623 line_height = 0
624 total_height = self.__padding
625 line_used = self.__padding
626 for legend in self.__legends:
627 (t_width, t_height) = ctx.text_extents(legend)[2:4]
628 item_width = self.__padding + self.__padding + t_width + self.__padding
629 item_height = t_height + self.__padding
630 if item_height > line_height:
631 line_height = item_height
632 if line_used + item_width > self.__width:
633 line_used = self.__padding + item_width
634 total_height += line_height
635 else:
636 line_used += item_width
637 x = line_used - item_width
638 ctx.rectangle(x, total_height, self.__padding, self.__padding)
639 ctx.set_source_rgb(0, 0, 0)
640 ctx.set_line_width(2)
641 ctx.stroke_preserve()
642 ctx.set_source_rgb(self.__colors[i].r, self.__colors[i].g, self.__colors[i].b)
643 ctx.fill()
644 ctx.move_to(x + self.__padding * 2, total_height + t_height)
645 ctx.set_source_rgb(0, 0, 0)
646 ctx.show_text(legend)
647 i += 1
648
649
650## TimelinesRenderer class
652 ## @var padding
653 # padding
654 ## @var timelines
655 # timelines
656 ## @var colors
657 # colors
658 ## @var start
659 # start
660 ## @var end
661 # end
662 ## @var left_width
663 # left width
664 ## @var right_width
665 # right width
666 ## @var max_text_height
667 # maximum text height
668 ## @var width
669 # width
670 ## @var height
671 # height
672 ## @var grey_background
673 # grey background
674 def __init__(self):
675 """! Initializer
676 @param self this object
677 """
678 self.padding = 10
679 return
680
681 def get_height(self):
682 """! Get Height
683 @param self this object
684 @return height
685 """
686 return self.height
687
688 def set_timelines(self, timelines, colors):
689 """! Set Timelines
690 @param self this object
691 @param timelines timelines
692 @param colors colors
693 @return none
694 """
695 self.timelines = timelines
696 self.colors = colors
697
698 def set_render_range(self, start, end):
699 """! Set Render Range
700 @param self this object
701 @param start start
702 @param end end
703 @return none
704 """
705 self.start = start
706 self.end = end
707
709 """! Get Data X Start
710 @param self: this object
711 @return X start
712 """
713 return (
714 self.padding / 2 + self.left_width + self.padding + self.right_width + self.padding / 2
715 )
716
717 def layout(self, width):
718 """! Get Data X Start
719 @param self this object
720 @param width width
721 @return none
722 """
723 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1)
724 ctx = cairo.Context(surface)
725 max_text_height = ctx.text_extents(
726 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789"
727 )[3]
728
729 left_width = 0
730 right_width = 0
731 left_n_lines = 0
732 range_n = 0
733 eventint_n = 0
734 eventstr_n = 0
735 for timeline in self.timelines.get_all():
736 left_n_lines += 1
737 t_width = ctx.text_extents(timeline.name)[2]
738 left_width = max(left_width, t_width)
739 for rang in timeline.get_ranges():
740 t_width = ctx.text_extents(rang.name)[2]
741 right_width = max(right_width, t_width)
742 range_n += 1
743 for events_int in timeline.get_events_int():
744 t_width = ctx.text_extents(events_int.name)[2]
745 right_width = max(right_width, t_width)
746 eventint_n += 1
747 for events_str in timeline.get_events_str():
748 t_width = ctx.text_extents(events_str.name)[2]
749 right_width = max(right_width, t_width)
750 eventstr_n += 1
751
752 left_height = left_n_lines * max_text_height + (left_n_lines - 1) * self.padding
753 right_n_lines = range_n + eventint_n + eventstr_n
754 right_height = (right_n_lines - 1) * self.padding + right_n_lines * max_text_height
755 right_data_height = (eventint_n + eventstr_n) * (max_text_height + 5) + range_n * 10
756 right_data_height += (right_n_lines - 1) * self.padding
757
758 height = max(left_height, right_height)
759 height = max(height, right_data_height)
760
761 self.left_width = left_width
762 self.right_width = right_width
763 self.max_text_height = max_text_height
764 self.width = width
765 self.height = height + self.padding
766
767 def draw_line(self, ctx, x, y, width, height):
768 """! Draw Line
769 @param self this object
770 @param ctx ctx
771 @param x x
772 @param y y
773 @param width width
774 @param height height
775 @return none
776 """
777 ctx.move_to(x, y)
778 ctx.rel_line_to(width, height)
779 ctx.close_path()
780 ctx.set_operator(cairo.OPERATOR_SOURCE)
781 ctx.set_line_width(1.0)
782 ctx.set_source_rgb(0, 0, 0)
783 ctx.stroke()
784
785 def draw_events(self, ctx, events, x, y, width, height):
786 """! Draw Event
787 @param self this object
788 @param ctx ctx
789 @param events events
790 @param x x
791 @param y y
792 @param width width
793 @param height height
794 @return none
795 """
796 if (self.grey_background % 2) == 0:
797 ctx.rectangle(x, y - self.padding / 2, width, height + self.padding)
798 ctx.set_source_rgb(0.9, 0.9, 0.9)
799 ctx.fill()
800 last_x_drawn = int(x)
801 (lo, hi) = events.get_events_bounds(self.start, self.end)
802 for event in events.events[lo:hi]:
803 real_x = int(x + (event.at - self.start) * width / (self.end - self.start))
804 if real_x > last_x_drawn + 2:
805 ctx.rectangle(real_x, y, 1, 1)
806 ctx.set_source_rgb(1, 0, 0)
807 ctx.stroke()
808 ctx.move_to(real_x, y + self.max_text_height)
809 ctx.set_source_rgb(0, 0, 0)
810 ctx.show_text(str(event.value))
811 last_x_drawn = real_x
812 self.grey_background += 1
813
814 def draw_ranges(self, ctx, ranges, x, y, width, height):
815 """! Draw Ranges
816 @param self this object
817 @param ctx ctx
818 @param ranges ranges
819 @param x x
820 @param y y
821 @param width width
822 @param height height
823 @return none
824 """
825 if (self.grey_background % 2) == 0:
826 ctx.rectangle(x, y - self.padding / 2, width, height + self.padding)
827 ctx.set_source_rgb(0.9, 0.9, 0.9)
828 ctx.fill()
829 last_x_drawn = int(x - 1)
830 (lo, hi) = ranges.get_ranges_bounds(self.start, self.end)
831 for data_range in ranges.ranges[lo:hi]:
832 s = max(data_range.start, self.start)
833 e = min(data_range.end, self.end)
834 x_start = int(x + (s - self.start) * width / (self.end - self.start))
835 x_end = int(x + (e - self.start) * width / (self.end - self.start))
836 if x_end > last_x_drawn:
837 ctx.rectangle(x_start, y, x_end - x_start, 10)
838 ctx.set_source_rgb(0, 0, 0)
839 ctx.stroke_preserve()
840 color = self.colors.lookup(data_range.value)
841 ctx.set_source_rgb(color.r, color.g, color.b)
842 ctx.fill()
843 last_x_drawn = x_end
844
845 self.grey_background += 1
846
847 def draw(self, ctx):
848 """! Draw
849 @param self this object
850 @param ctx ctx
851 @return none
852 """
853 timeline_top = 0
854 top_y = self.padding / 2
855 left_x_start = self.padding / 2
856 left_x_end = left_x_start + self.left_width
857 right_x_start = left_x_end + self.padding
858 right_x_end = right_x_start + self.right_width
859 data_x_start = right_x_end + self.padding / 2
860 data_x_end = self.width
861 data_width = data_x_end - data_x_start
862 cur_y = top_y
863 self.draw_line(ctx, 0, 0, self.width, 0)
865 for timeline in self.timelines.get_all():
866 (y_bearing, t_width, t_height) = ctx.text_extents(timeline.name)[1:4]
867 ctx.move_to(left_x_start, cur_y + self.max_text_height - (t_height + y_bearing))
868 ctx.show_text(timeline.name)
869 for events_int in timeline.get_events_int():
870 (y_bearing, t_width, t_height) = ctx.text_extents(events_int.name)[1:4]
871 ctx.move_to(right_x_start, cur_y + self.max_text_height - (t_height + y_bearing))
872 ctx.show_text(events_int.name)
873 self.draw_events(
874 ctx, events_int, data_x_start, cur_y, data_width, self.max_text_height + 5
875 )
876 cur_y += self.max_text_height + 5 + self.padding
877 self.draw_line(
878 ctx,
879 right_x_start - self.padding / 2,
880 cur_y - self.padding / 2,
881 self.right_width + self.padding,
882 0,
883 )
884
885 for events_str in timeline.get_events_str():
886 (y_bearing, t_width, t_height) = ctx.text_extents(events_str.name)[1:4]
887 ctx.move_to(right_x_start, cur_y + self.max_text_height - (t_height + y_bearing))
888 ctx.show_text(events_str.name)
889 self.draw_events(
890 ctx, events_str, data_x_start, cur_y, data_width, self.max_text_height + 5
891 )
892 cur_y += self.max_text_height + 5 + self.padding
893 self.draw_line(
894 ctx,
895 right_x_start - self.padding / 2,
896 cur_y - self.padding / 2,
897 self.right_width + self.padding,
898 0,
899 )
900 for ranges in timeline.get_ranges():
901 (y_bearing, t_width, t_height) = ctx.text_extents(ranges.name)[1:4]
902 ctx.move_to(right_x_start, cur_y + self.max_text_height - (t_height + y_bearing))
903 ctx.show_text(ranges.name)
904 self.draw_ranges(ctx, ranges, data_x_start, cur_y, data_width, 10)
905 cur_y += self.max_text_height + self.padding
906 self.draw_line(
907 ctx,
908 right_x_start - self.padding / 2,
909 cur_y - self.padding / 2,
910 self.right_width + self.padding,
911 0,
912 )
913 self.draw_line(ctx, 0, cur_y - self.padding / 2, self.width, 0)
914 bot_y = cur_y - self.padding / 2
915 self.draw_line(ctx, left_x_end + self.padding / 2, 0, 0, bot_y)
916 self.draw_line(ctx, right_x_end + self.padding / 2, 0, 0, bot_y)
917
918
919## ScaleRenderer class
921 ## @var __top
922 # top
923 ## @var __lo
924 # lo
925 ## @var __hi
926 # hi
927 ## @var __delta
928 # delta
929 ## @var __width
930 # width
931 ## @var __height
932 # height
933 ## @var max_text_height
934 # maximum text height
935 def __init__(self):
936 """! Initializer
937 @param self this object
938 """
939 self.__top = 0
940 return
941
942 def set_bounds(self, lo, hi):
943 """! Set Bounds
944 @param self this object
945 @param lo lo
946 @param hi hi
947 @return none
948 """
949 self.__lo = lo
950 self.__hi = hi
951
952 def get_position(self, x):
953 """! Get Position
954 @param self this object
955 @param x x
956 @return real x
957 """
958 real_x = (x - self.__lo) * self.__width / (self.__hi - self.__lo)
959 return real_x
960
961 def set_top(self):
962 """! Set Top
963 @param self this object
964 @return none
965 """
966 self.__top = 1
967
968 def set_bot(self):
969 """! Set Bottom
970 @param self this object
971 @return none
972 """
973 self.__top = 0
974
975 def layout(self, width):
976 """! Layout
977 @param self this object
978 @param width width
979 @return none
980 """
981 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1)
982 ctx = cairo.Context(surface)
983
984 # calculate scale delta
985 data_delta = self.__hi - self.__lo
986 closest = 1
987 while (closest * 10) < data_delta:
988 closest *= 10
989 if (data_delta / closest) == 0:
990 delta = closest
991 elif (data_delta / closest) == 1:
992 delta = closest / 10
993 else:
994 delta = closest
995 start = self.__lo - (self.__lo % delta) + delta
996 end = self.__hi - (self.__hi % delta)
997
998 self.__delta = delta
999 self.__width = width
1000
1001 # calculate text height
1002 max_text_height = ctx.text_extents(
1003 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789"
1004 )[3]
1005 self.max_text_height = max_text_height
1006 height = max_text_height + 10
1007 self.__height = height
1008
1009 def get_height(self):
1010 """! Get Height
1011 @param self: this object
1012 @return height
1013 """
1014 return self.__height
1015
1016 def draw(self, ctx):
1017 """! Draw
1018 @param self this object
1019 @param ctx ctx
1020 @return none
1021 """
1022 delta = self.__delta
1023 start = self.__lo - (self.__lo % delta) + delta
1024 end = self.__hi - (self.__hi % delta)
1025
1026 if self.__top == 1:
1027 s = -1
1028 else:
1029 s = 1
1030 # print scale points
1031 ctx.set_source_rgb(0, 0, 0)
1032 ctx.set_line_width(1.0)
1033 ticks = range(int(start), int(end + delta), int(delta))
1034 for x in ticks:
1035 real_x = (x - self.__lo) * self.__width / (self.__hi - self.__lo)
1036 ctx.move_to(real_x, 0)
1037 ctx.line_to(real_x, 5 * s)
1038 ctx.close_path()
1039 ctx.stroke()
1040 (t_y_bearing, t_width, t_height) = ctx.text_extents(str(x))[1:4]
1041 if self.__top:
1042 text_delta = t_height + t_y_bearing
1043 else:
1044 text_delta = -t_y_bearing
1045 ctx.move_to(real_x - t_width / 2, (5 + 5 + text_delta) * s)
1046 ctx.show_text(str(x))
1047 # draw subticks
1048 delta /= 10
1049 if delta > 0:
1050 start = self.__lo - (self.__lo % delta) + delta
1051 end = self.__hi - (self.__hi % delta)
1052 for x in range(int(start), int(end + delta), int(delta)):
1053 real_x = (x - self.__lo) * self.__width / (self.__hi - self.__lo)
1054 ctx.move_to(real_x, 0)
1055 ctx.line_to(real_x, 3 * s)
1056 ctx.close_path()
1057 ctx.stroke()
1058
1059
1060## GraphicRenderer class
1062 ## @var __start
1063 # start
1064 ## @var __end
1065 # end
1066 ## @var __mid_scale
1067 # mid scale
1068 ## @var __bot_scale
1069 # bottom scale
1070 ## @var __width
1071 # width
1072 ## @var __height
1073 # height
1074 ## @var __r_start
1075 # start
1076 ## @var __r_end
1077 # end
1078 ## @var __data
1079 # data
1080 ## @var __mid_scale
1081 # mid scale
1082 ## @var __top_legend
1083 # top legend
1084 def __init__(self, start, end):
1085 """! Initializer
1086 @param self this object
1087 @param start start
1088 @param end end
1089 """
1090 self.__start = float(start)
1091 self.__end = float(end)
1093 self.__mid_scale.set_top()
1095 self.__bot_scale.set_bounds(start, end)
1096 self.__bot_scale.set_bot()
1097 self.__width = 1
1098 self.__height = 1
1099
1100 def get_width(self):
1101 """! Get Width
1102 @param self: this object
1103 @return width
1104 """
1105 return self.__width
1106
1107 def get_height(self):
1108 """! Get Height
1109 @param self this object
1110 @return height
1111 """
1112 return self.__height
1113
1114 # return x, y, width, height
1116 """! Get Data Rectangle
1117 @param self this object
1118 @return rectangle
1119 """
1120 y_start = self.__top_legend.get_height()
1121 x_start = self.__data.get_data_x_start()
1122 return (x_start, y_start, self.__width - x_start, self.__data.get_height())
1123
1124 def scale_data(self, x):
1125 """! Get Data Rectangle
1126 @param self this object
1127 @param x x
1128 @return scaled x
1129 """
1130 x_start = self.__data.get_data_x_start()
1131 x_scaled = x / (self.__width - x_start) * (self.__r_end - self.__r_start)
1132 return x_scaled
1133
1134 # return x, y, width, height
1136 """! Get Selection Rectangle
1137 @param self this object
1138 @return rectangle
1139 """
1140 y_start = (
1142 + self.__data.get_height()
1143 + self.__mid_scale.get_height()
1144 + 20
1145 )
1146 y_height = self.__bot_scale.get_height() + 20
1147 x_start = self.__bot_scale.get_position(self.__r_start)
1148 x_end = self.__bot_scale.get_position(self.__r_end)
1149 return (x_start, y_start, x_end - x_start, y_height)
1150
1151 def scale_selection(self, x):
1152 """! Scale Selection
1153 @param self this object
1154 @param x the X
1155 @return scaled X
1156 """
1157 x_scaled = x / self.__width * (self.__end - self.__start)
1158 return x_scaled
1159
1160 def set_range(self, start, end):
1161 """! Set Range
1162 @param self this object
1163 @param start start
1164 @param end end
1165 @return none
1166 """
1167 s = min(start, end)
1168 e = max(start, end)
1169 start = max(self.__start, s)
1170 end = min(self.__end, e)
1171 self.__r_start = start
1172 self.__r_end = end
1173 self.__data.set_render_range(start, end)
1174 self.__mid_scale.set_bounds(start, end)
1175 self.layout(self.__width, self.__height)
1176
1177 def get_range(self):
1178 """! Get Range
1179 @param self this object
1180 @return range
1181 """
1182 return (self.__r_start, self.__r_end)
1183
1184 def set_data(self, data):
1185 """! Set Date
1186 @param self this object
1187 @param data data
1188 @return none
1189 """
1190 self.__data = data
1191
1192 def set_top_legend(self, top_legend):
1193 """! Set Top Legend
1194 @param self this object
1195 @param top_legend The legend
1196 @return none
1197 """
1198 self.__top_legend = top_legend
1199
1200 def layout(self, width, height):
1201 """! Set Layout
1202 @param self this object
1203 @param width width
1204 @param height height
1205 @return none
1206 """
1207 self.__width = width
1208 self.__height = height
1209 self.__top_legend.layout(width)
1210 top_legend_height = self.__top_legend.get_height()
1211 self.__data.layout(width)
1212 self.__mid_scale.layout(width - self.__data.get_data_x_start())
1213 self.__bot_scale.layout(width)
1214 return
1215
1216 def __x_pixel(self, x, width):
1217 """! X Pixel
1218 @param self this object
1219 @param x x
1220 @param width width
1221 @return x pixel
1222 """
1223 new_x = (x - self.__start) * width / (self.__end - self.__start)
1224 return new_x
1225
1226 def draw(self, ctx):
1227 """! Draw
1228 @param self this object
1229 @param ctx ctx
1230 @return none
1231 """
1232 # default background is white
1233 ctx.save()
1234 ctx.set_source_rgb(1, 1, 1)
1235 ctx.set_operator(cairo.OPERATOR_SOURCE)
1236 ctx.rectangle(0, 0, self.__width, self.__height)
1237 ctx.fill()
1238
1239 # top legend
1240 ctx.save()
1241 self.__top_legend.draw(ctx)
1242 top_legend_height = self.__top_legend.get_height()
1243 ctx.restore()
1244
1245 # separation line
1246 ctx.move_to(0, top_legend_height)
1247 ctx.line_to(self.__width, top_legend_height)
1248 ctx.close_path()
1249 ctx.set_line_width(2)
1250 ctx.set_source_rgb(0, 0, 0)
1251 ctx.stroke()
1252
1253 # data
1254 ctx.save()
1255 ctx.translate(0, top_legend_height)
1256 self.__data.draw(ctx)
1257 ctx.restore()
1258
1259 # scale below data
1260 ctx.save()
1261 ctx.translate(
1262 self.__data.get_data_x_start(),
1263 top_legend_height + self.__data.get_height() + self.__mid_scale.get_height(),
1264 )
1265 self.__mid_scale.draw(ctx)
1266 ctx.restore()
1267
1268 height_used = top_legend_height + self.__data.get_height() + self.__mid_scale.get_height()
1269
1270 # separation between scale and left pane
1271 ctx.move_to(self.__data.get_data_x_start(), height_used)
1272 ctx.rel_line_to(0, -self.__mid_scale.get_height())
1273 ctx.close_path()
1274 ctx.set_source_rgb(0, 0, 0)
1275 ctx.set_line_width(2)
1276 ctx.stroke()
1277
1278 # separation below scale
1279 ctx.move_to(0, height_used)
1280 ctx.line_to(self.__width, height_used)
1281 ctx.close_path()
1282 ctx.set_line_width(2)
1283 ctx.set_source_rgb(0, 0, 0)
1284 ctx.stroke()
1285
1286 select_start = self.__bot_scale.get_position(self.__r_start)
1287 select_end = self.__bot_scale.get_position(self.__r_end)
1288
1289 # left connection between top scale and bottom scale
1290 ctx.move_to(0, height_used)
1291 ctx.line_to(self.__data.get_data_x_start(), height_used)
1292 ctx.line_to(select_start, height_used + 20)
1293 ctx.line_to(0, height_used + 20)
1294 ctx.line_to(0, height_used)
1295 ctx.set_source_rgb(0, 0, 0)
1296 ctx.set_line_width(1)
1297 ctx.stroke_preserve()
1298 ctx.set_source_rgb(0.9, 0.9, 0.9)
1299 ctx.fill()
1300
1301 # right connection between top scale and bottom scale
1302 ctx.move_to(self.__width, height_used)
1303 ctx.line_to(self.__width, height_used + 20)
1304 ctx.line_to(select_end, height_used + 20)
1305 ctx.line_to(self.__width, height_used)
1306 ctx.set_source_rgb(0, 0, 0)
1307 ctx.set_line_width(1)
1308 ctx.stroke_preserve()
1309 ctx.set_source_rgb(0.9, 0.9, 0.9)
1310 ctx.fill()
1311
1312 height_used += 20
1313
1314 # unused area background
1315 unused_start = self.__bot_scale.get_position(self.__r_start)
1316 unused_end = self.__bot_scale.get_position(self.__r_end)
1317 unused_height = self.__bot_scale.get_height() + 20
1318 ctx.rectangle(0, height_used, unused_start, unused_height)
1319 ctx.rectangle(unused_end, height_used, self.__width - unused_end, unused_height)
1320 ctx.set_source_rgb(0.9, 0.9, 0.9)
1321 ctx.fill()
1322
1323 # border line around bottom scale
1324 ctx.move_to(unused_end, height_used)
1325 ctx.line_to(self.__width, height_used)
1326 ctx.line_to(self.__width, height_used + unused_height)
1327 ctx.line_to(0, height_used + unused_height)
1328 ctx.line_to(0, height_used)
1329 ctx.line_to(unused_start, height_used)
1330 ctx.close_path()
1331 ctx.set_line_width(2)
1332 ctx.set_source_rgb(0, 0, 0)
1333 ctx.stroke()
1334 ctx.move_to(unused_start, height_used)
1335 ctx.line_to(unused_end, height_used)
1336 ctx.close_path()
1337 ctx.set_line_width(1)
1338 ctx.set_source_rgb(0.9, 0.9, 0.9)
1339 ctx.stroke()
1340
1341 # unused area dot borders
1342 ctx.save()
1343 ctx.move_to(max(unused_start, 2), height_used)
1344 ctx.rel_line_to(0, unused_height)
1345 ctx.move_to(min(unused_end, self.__width - 2), height_used)
1346 ctx.rel_line_to(0, unused_height)
1347 ctx.set_dash([5], 0)
1348 ctx.set_source_rgb(0, 0, 0)
1349 ctx.set_line_width(1)
1350 ctx.stroke()
1351 ctx.restore()
1352
1353 # bottom scale
1354 ctx.save()
1355 ctx.translate(0, height_used)
1356 self.__bot_scale.draw(ctx)
1357 ctx.restore()
1358
1359
1360## GtkGraphicRenderer class
1361class GtkGraphicRenderer(gtk.DrawingArea):
1362 ## @var __data
1363 # data
1364 ## @var __moving_left
1365 # moving left
1366 ## @var __moving_right
1367 # moving right
1368 ## @var __moving_both
1369 # moving both
1370 ## @var __moving_top
1371 # moving top
1372 ## @var __force_full_redraw
1373 # full redraw
1374 ## @var __moving_left_cur
1375 # moving left cur
1376 ## @var __moving_right_cur
1377 # moving right cur
1378 ## @var __moving_both_start
1379 # moving both start
1380 ## @var __moving_both_cur
1381 # moving both cur
1382 ## @var __moving_top_cur
1383 # moving top cur
1384 ## @var __moving_top_start
1385 # moving top start
1386 ## @var __width
1387 # width
1388 ## @var __height
1389 # height
1390 ## @var __buffer_surface
1391 # __buffer_surface
1392 ## @var expose
1393 # expose function
1394 ## @var size_allocate
1395 # size_allocate function
1396 ## @var motion_notify
1397 # motion_notify function
1398 ## @var button_press
1399 # button_press function
1400 ## @var button_release
1401 # button_release function
1402 def __init__(self, data):
1403 """! Initializer
1404 @param self this object
1405 @param data data
1406 """
1407 super(GtkGraphicRenderer, self).__init__()
1408 self.__data = data
1409 self.__moving_left = False
1410 self.__moving_right = False
1411 self.__moving_both = False
1412 self.__moving_top = False
1414 self.add_events(gtk.gdk.POINTER_MOTION_MASK)
1415 self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
1416 self.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
1417 self.connect("expose_event", self.exposeexpose)
1418 self.connect("size-allocate", self.size_allocatesize_allocate)
1419 self.connect("motion-notify-event", self.motion_notifymotion_notify)
1420 self.connect("button-press-event", self.button_pressbutton_press)
1421 self.connect("button-release-event", self.button_releasebutton_release)
1422
1424 """! Set Smaller Zoom
1425 @param self this object
1426 @return none
1427 """
1428 (start, end) = self.__data.get_range()
1429 self.__data.set_range(start, start + (end - start) * 2)
1430 self.__force_full_redraw = True
1431 self.queue_draw()
1432
1434 """! Set Bigger Zoom
1435 @param self this object
1436 @return none
1437 """
1438 (start, end) = self.__data.get_range()
1439 self.__data.set_range(start, start + (end - start) / 2)
1440 self.__force_full_redraw = True
1441 self.queue_draw()
1442
1443 def output_png(self, filename):
1444 """! Output PNG
1445 @param self this object
1446 @param filename file name
1447 @return none
1448 """
1449 surface = cairo.ImageSurface(
1450 cairo.FORMAT_ARGB32, self.__data.get_width(), self.__data.get_height()
1451 )
1452 ctx = cairo.Context(self.__buffer_surface)
1453 self.__data.draw(ctx)
1454 surface.write_to_png(filename)
1455
1456 def button_press(self, widget, event):
1457 """! Button Press
1458 @param self this object
1459 @param widget widget
1460 @param event event
1461 @return true if button has been pressed otherwise false
1462 """
1463 (x, y, width, height) = self.__data.get_selection_rectangle()
1464 (d_x, d_y, d_width, d_height) = self.__data.get_data_rectangle()
1465 if event.y > y and event.y < y + height:
1466 if abs(event.x - x) < 5:
1467 self.__moving_left = True
1468 return True
1469 if abs(event.x - (x + width)) < 5:
1470 self.__moving_right = True
1471 return True
1472 if event.x > x and event.x < x + width:
1473 self.__moving_both = True
1474 self.__moving_both_start = event.x
1475 self.__moving_both_cur = event.x
1476 return True
1477 if event.y > d_y and event.y < (d_y + d_height):
1478 if event.x > d_x and event.x < (d_x + d_width):
1479 self.__moving_top = True
1480 self.__moving_top_start = event.x
1481 self.__moving_top_cur = event.x
1482 return True
1483 return False
1484
1485 def button_release(self, widget, event):
1486 """! Button Release
1487 @param self this object
1488 @param widget widget
1489 @param event event
1490 @return true if button was released otherwise false
1491 """
1492 if self.__moving_left:
1493 self.__moving_left = False
1494 left = self.__data.scale_selection(self.__moving_left_cur)
1495 right = self.__data.get_range()[1]
1496 self.__data.set_range(left, right)
1497 self.__force_full_redraw = True
1498 self.queue_draw()
1499 return True
1500 if self.__moving_right:
1501 self.__moving_right = False
1502 right = self.__data.scale_selection(self.__moving_right_cur)
1503 left = self.__data.get_range()[0]
1504 self.__data.set_range(left, right)
1505 self.__force_full_redraw = True
1506 self.queue_draw()
1507 return True
1508 if self.__moving_both:
1509 self.__moving_both = False
1510 delta = self.__data.scale_selection(self.__moving_both_cur - self.__moving_both_start)
1511 (left, right) = self.__data.get_range()
1512 self.__data.set_range(left + delta, right + delta)
1513 self.__force_full_redraw = True
1514 self.queue_draw()
1515 return True
1516 if self.__moving_top:
1517 self.__moving_top = False
1518 return False
1519
1520 def motion_notify(self, widget, event):
1521 """! Motion Notify
1522 @param self this object
1523 @param widget widget
1524 @param event event
1525 @return true if moving otherwise false
1526 """
1527 (x, y, width, height) = self.__data.get_selection_rectangle()
1528 if self.__moving_left:
1529 if event.x <= 0:
1531 elif event.x >= x + width:
1532 self.__moving_left_cur = x + width
1533 else:
1534 self.__moving_left_cur = event.x
1535 self.queue_draw_area(0, int(y), int(self.__width), int(height))
1536 return True
1537 if self.__moving_right:
1538 if event.x >= self.__width:
1539 self.__moving_right = self.__width
1540 elif event.x < x:
1542 else:
1543 self.__moving_right_cur = event.x
1544 self.queue_draw_area(0, int(y), int(self.__width), int(height))
1545 return True
1546 if self.__moving_both:
1547 cur_e = self.__width - (x + width - self.__moving_both_start)
1548 cur_s = self.__moving_both_start - x
1549 if event.x < cur_s:
1550 self.__moving_both_cur = cur_s
1551 elif event.x > cur_e:
1552 self.__moving_both_cur = cur_e
1553 else:
1554 self.__moving_both_cur = event.x
1555 self.queue_draw_area(0, int(y), int(self.__width), int(height))
1556 return True
1557 if self.__moving_top:
1558 self.__moving_top_cur = event.x
1559 delta = self.__data.scale_data(self.__moving_top_start - self.__moving_top_cur)
1560 (left, right) = self.__data.get_range()
1561 self.__data.set_range(left + delta, right + delta)
1562 self.__force_full_redraw = True
1563 self.__moving_top_start = event.x
1564 self.queue_draw()
1565 return True
1566 (d_x, d_y, d_width, d_height) = self.__data.get_data_rectangle()
1567 if event.y > y and event.y < y + height:
1568 if abs(event.x - x) < 5 or abs(event.x - (x + width)) < 5:
1569 widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.SB_H_DOUBLE_ARROW))
1570 return True
1571 if event.x > x and event.x < x + width:
1572 widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
1573 return True
1574 if event.y > d_y and event.y < (d_y + d_height):
1575 if event.x > d_x and event.x < (d_x + d_width):
1576 widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
1577 return True
1578 widget.window.set_cursor(None)
1579 return False
1580
1581 def size_allocate(self, widget, allocation):
1582 """! Size Allocate
1583 @param self this object
1584 @param widget widget
1585 @param allocation allocation
1586 @return none
1587 """
1588 self.__width = allocation.width
1589 self.__height = allocation.height
1590 self.__data.layout(allocation.width, allocation.height)
1591 self.__force_full_redraw = True
1592 self.queue_draw()
1593
1594 def expose(self, widget, event):
1595 """! Expose
1596 @param self this object
1597 @param widget widget
1598 @param event event
1599 @return false
1600 """
1601 if self.__force_full_redraw:
1602 self.__buffer_surface = cairo.ImageSurface(
1603 cairo.FORMAT_ARGB32, self.__data.get_width(), self.__data.get_height()
1604 )
1605 ctx = cairo.Context(self.__buffer_surface)
1606 self.__data.draw(ctx)
1607 self.__force_full_redraw = False
1608 ctx = widget.window.cairo_create()
1609 ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
1610 ctx.clip()
1611 ctx.set_source_surface(self.__buffer_surface)
1612 ctx.paint()
1613 (x, y, width, height) = self.__data.get_selection_rectangle()
1614 if self.__moving_left:
1615 ctx.move_to(max(self.__moving_left_cur, 2), y)
1616 ctx.rel_line_to(0, height)
1617 ctx.close_path()
1618 ctx.set_line_width(1)
1619 ctx.set_source_rgb(0, 0, 0)
1620 ctx.stroke()
1621 if self.__moving_right:
1622 ctx.move_to(min(self.__moving_right_cur, self.__width - 2), y)
1623 ctx.rel_line_to(0, height)
1624 ctx.close_path()
1625 ctx.set_line_width(1)
1626 ctx.set_source_rgb(0, 0, 0)
1627 ctx.stroke()
1628 if self.__moving_both:
1629 delta_x = self.__moving_both_cur - self.__moving_both_start
1630 left_x = x + delta_x
1631 ctx.move_to(x + delta_x, y)
1632 ctx.rel_line_to(0, height)
1633 ctx.close_path()
1634 ctx.move_to(x + width + delta_x, y)
1635 ctx.rel_line_to(0, height)
1636 ctx.close_path()
1637 ctx.set_source_rgb(0, 0, 0)
1638 ctx.set_line_width(1)
1639 ctx.stroke()
1640 return False
1641
1642
1643## MainWindow class
1645 ## @var __window
1646 # window
1647 ## @var __render
1648 # render
1649 ## @var __dialog
1650 # dialog
1651 ## @var __set_smaller_cb
1652 # __set_smaller_cb function
1653 ## @var __set_bigger_cb
1654 # __set_bigger_cb function
1655 ## @var __output_png_cb
1656 # __output_png_cb function
1657 ## @var __dialog_response_cb
1658 # __dialog_response_cb function
1659 def __init__(self):
1660 """! Initializer
1661 @param self this object
1662 """
1663 return
1664
1665 def run(self, graphic):
1666 """! Run function
1667 @param self this object
1668 @param graphic graphic
1669 @return none
1670 """
1671 window = gtk.Window()
1672 self.__window = window
1673 window.set_default_size(200, 200)
1674 vbox = gtk.VBox()
1675 window.add(vbox)
1676 render = GtkGraphicRenderer(graphic)
1677 self.__render = render
1678 vbox.pack_end(render, True, True, 0)
1679 hbox = gtk.HBox()
1680 vbox.pack_start(hbox, False, False, 0)
1681 smaller_zoom = gtk.Button("Zoom Out")
1682 smaller_zoom.connect("clicked", self.__set_smaller_cb__set_smaller_cb)
1683 hbox.pack_start(smaller_zoom)
1684 bigger_zoom = gtk.Button("Zoom In")
1685 bigger_zoom.connect("clicked", self.__set_bigger_cb__set_bigger_cb)
1686 hbox.pack_start(bigger_zoom)
1687 output_png = gtk.Button("Output Png")
1688 output_png.connect("clicked", self.__output_png_cb__output_png_cb)
1689 hbox.pack_start(output_png)
1690 window.connect("destroy", gtk.main_quit)
1691 window.show_all()
1692 # gtk.bindings_activate(gtk.main_quit, 'q', 0)
1693 gtk.main()
1694
1695 def __set_smaller_cb(self, widget):
1696 """! Set Smaller Callback
1697 @param self this object
1698 @param widget widget
1699 @return none
1700 """
1701 self.__render.set_smaller_zoom()
1702
1703 def __set_bigger_cb(self, widget):
1704 """! Set Bigger Callback
1705 @param self this object
1706 @param widget widget
1707 @return none
1708 """
1709 self.__render.set_bigger_zoom()
1710
1711 def __output_png_cb(self, widget):
1712 """! Output PNG Callback
1713 @param self this object
1714 @param widget widget
1715 @return none
1716 """
1717 dialog = gtk.FileChooserDialog(
1718 "Output Png", self.__window, gtk.FILE_CHOOSER_ACTION_SAVE, ("Save", 1)
1719 )
1720 self.__dialog = dialog
1721 dialog.set_default_response(1)
1722 dialog.connect("response", self.__dialog_response_cb__dialog_response_cb)
1723 dialog.show()
1724
1725 def __dialog_response_cb(self, widget, response):
1726 """! Dialog Response Callback
1727 @param self this object
1728 @param widget widget
1729 @param response response
1730 @return none
1731 """
1732 if response == 1:
1733 filename = self.__dialog.get_filename()
1734 self.__render.output_png(filename)
1735 widget.hide()
1736
1737
1738## read_data function
1739def read_data(filename):
1740 timelines = Timelines()
1741 colors = Colors()
1742 m1 = re.compile("range ([^ ]+) ([^ ]+) ([^ ]+) ([0-9]+) ([0-9]+)")
1743 m2 = re.compile("event-str ([^ ]+) ([^ ]+) ([^ ]+) ([0-9]+)")
1744 m3 = re.compile("event-int ([^ ]+) ([^ ]+) ([0-9]+) ([0-9]+)")
1745 m4 = re.compile("color ([^ ]+) #([a-fA-F0-9]{2,2})([a-fA-F0-9]{2,2})([a-fA-F0-9]{2,2})")
1746
1747 with open(filename, encoding="utf-8") as fh:
1748 for line in fh.readlines():
1749 m = m1.match(line)
1750 if m:
1751 line_name = m.group(1)
1752 timeline = timelines.get(m.group(1))
1753 rang = timeline.get_range(m.group(2))
1754 data_range = DataRange()
1755 data_range.value = m.group(3)
1756 data_range.start = int(m.group(4))
1757 data_range.end = int(m.group(5))
1758 rang.add_range(data_range)
1759 continue
1760 m = m2.match(line)
1761 if m:
1762 line_name = m.group(1)
1763 timeline = timelines.get(m.group(1))
1764 ev = timeline.get_event_str(m.group(2))
1765 event = EventString()
1766 event.value = m.group(3)
1767 event.at = int(m.group(4))
1768 ev.add_event(event)
1769 continue
1770 m = m3.match(line)
1771 if m:
1772 line_name = m.group(1)
1773 timeline = timelines.get(m.group(1))
1774 ev = timeline.get_event_int(m.group(2))
1775 event = EventInt()
1776 event.value = int(m.group(3))
1777 event.at = int(m.group(4))
1778 ev.add_event(event)
1779 continue
1780
1781 m = m4.match(line)
1782 if m:
1783 r = int(m.group(2), 16)
1784 g = int(m.group(3), 16)
1785 b = int(m.group(4), 16)
1786 color = Color(r / 255, g / 255, b / 255)
1787 colors.add(m.group(1), color)
1788 continue
1789 timelines.sort()
1790 return (colors, timelines)
1791
1792
1793def main():
1794 (colors, timelines) = read_data(sys.argv[1])
1795 (lower_bound, upper_bound) = timelines.get_bounds()
1796 graphic = GraphicRenderer(lower_bound, upper_bound)
1797 top_legend = TopLegendRenderer()
1798 range_values = timelines.get_all_range_values()
1799 range_colors = []
1800 for range_value in range_values:
1801 range_colors.append(colors.lookup(range_value))
1802 top_legend.set_legends(range_values, range_colors)
1803 graphic.set_top_legend(top_legend)
1804 data = TimelinesRenderer()
1805 data.set_timelines(timelines, colors)
1806 graphic.set_data(data)
1807
1808 # default range
1809 range_mid = (upper_bound - lower_bound) / 2
1810 range_width = (upper_bound - lower_bound) / 10
1811 range_lo = range_mid - range_width / 2
1812 range_hi = range_mid + range_width / 2
1813 graphic.set_range(range_lo, range_hi)
1814
1815 main_window = MainWindow()
1816 main_window.run(graphic)
1817
1818
1819main()
Color class.
Definition grid.py:473
__init__(self, r=0.0, g=0.0, b=0.0)
Initializer.
Definition grid.py:480
set(self, r, g, b)
Set color.
Definition grid.py:491
g
green
Definition grid.py:488
b
blue
Definition grid.py:489
Colors class.
Definition grid.py:505
add(self, name, color)
Add.
Definition grid.py:526
__init__(self)
Initializer.
Definition grid.py:520
lookup(self, name)
Lookup name.
Definition grid.py:535
list default_colors
default colors XXX add more
Definition grid.py:511
__colors
colors
Definition grid.py:524
DataRange class.
Definition grid.py:11
value
value
Definition grid.py:27
start
start
Definition grid.py:25
__init__(self, start=0, end=0, value="")
Initializer.
Definition grid.py:18
EventFloat class.
Definition grid.py:47
__init__(self, at=0, value=0.0)
Initializer.
Definition grid.py:52
value
value
Definition grid.py:59
EventInt class.
Definition grid.py:63
__init__(self, at=0, value=0.0)
Initializer.
Definition grid.py:68
value
value
Definition grid.py:75
EventString class.
Definition grid.py:31
__init__(self, at=0, value="")
Initializer.
Definition grid.py:36
GraphicRenderer class.
Definition grid.py:1061
__x_pixel(self, x, width)
X Pixel.
Definition grid.py:1216
__mid_scale
mid scale
Definition grid.py:1092
layout(self, width, height)
Set Layout.
Definition grid.py:1200
get_data_rectangle(self)
Get Data Rectangle.
Definition grid.py:1115
__init__(self, start, end)
Initializer.
Definition grid.py:1084
scale_selection(self, x)
Scale Selection.
Definition grid.py:1151
get_range(self)
Get Range.
Definition grid.py:1177
__bot_scale
bottom scale
Definition grid.py:1094
__top_legend
top legend
Definition grid.py:1198
set_top_legend(self, top_legend)
Set Top Legend.
Definition grid.py:1192
set_data(self, data)
Set Date.
Definition grid.py:1184
get_selection_rectangle(self)
Get Selection Rectangle.
Definition grid.py:1135
scale_data(self, x)
Get Data Rectangle.
Definition grid.py:1124
get_width(self)
Get Width.
Definition grid.py:1100
draw(self, ctx)
Draw.
Definition grid.py:1226
set_range(self, start, end)
Set Range.
Definition grid.py:1160
get_height(self)
Get Height.
Definition grid.py:1107
GtkGraphicRenderer class.
Definition grid.py:1361
button_press
button_press function
Definition grid.py:1420
__force_full_redraw
full redraw
Definition grid.py:1413
__moving_top_start
moving top start
Definition grid.py:1480
__moving_both_cur
moving both cur
Definition grid.py:1475
motion_notify(self, widget, event)
Motion Notify.
Definition grid.py:1520
motion_notify
motion_notify function
Definition grid.py:1419
__moving_right
moving right
Definition grid.py:1410
button_release(self, widget, event)
Button Release.
Definition grid.py:1485
__moving_left
moving left
Definition grid.py:1409
set_smaller_zoom(self)
Set Smaller Zoom.
Definition grid.py:1423
__moving_right_cur
moving right cur
Definition grid.py:1541
__buffer_surface
__buffer_surface
Definition grid.py:1602
__moving_top_cur
moving top cur
Definition grid.py:1481
expose
expose function
Definition grid.py:1417
button_press(self, widget, event)
Button Press.
Definition grid.py:1456
set_bigger_zoom(self)
Set Bigger Zoom.
Definition grid.py:1433
__moving_top
moving top
Definition grid.py:1412
__moving_both_start
moving both start
Definition grid.py:1474
__init__(self, data)
Initializer.
Definition grid.py:1402
button_release
button_release function
Definition grid.py:1421
expose(self, widget, event)
Expose.
Definition grid.py:1594
__moving_both
moving both
Definition grid.py:1411
size_allocate(self, widget, allocation)
Size Allocate.
Definition grid.py:1581
__moving_left_cur
moving left cur
Definition grid.py:1530
size_allocate
size_allocate function
Definition grid.py:1418
output_png(self, filename)
Output PNG.
Definition grid.py:1443
MainWindow class.
Definition grid.py:1644
__output_png_cb(self, widget)
Output PNG Callback.
Definition grid.py:1711
__set_bigger_cb
__set_bigger_cb function
Definition grid.py:1685
run(self, graphic)
Run function.
Definition grid.py:1665
__init__(self)
Initializer.
Definition grid.py:1659
__dialog_response_cb
__dialog_response_cb function
Definition grid.py:1722
__set_smaller_cb
__set_smaller_cb function
Definition grid.py:1682
__dialog
dialog
Definition grid.py:1720
__window
window
Definition grid.py:1672
__set_bigger_cb(self, widget)
Set Bigger Callback.
Definition grid.py:1703
__output_png_cb
__output_png_cb function
Definition grid.py:1688
__set_smaller_cb(self, widget)
Set Smaller Callback.
Definition grid.py:1695
__render
render
Definition grid.py:1677
__dialog_response_cb(self, widget, response)
Dialog Response Callback.
Definition grid.py:1725
ScaleRenderer class.
Definition grid.py:920
draw(self, ctx)
Draw.
Definition grid.py:1016
set_bot(self)
Set Bottom.
Definition grid.py:968
get_height(self)
Get Height.
Definition grid.py:1009
set_bounds(self, lo, hi)
Set Bounds.
Definition grid.py:942
max_text_height
maximum text height
Definition grid.py:1005
__init__(self)
Initializer.
Definition grid.py:935
layout(self, width)
Layout.
Definition grid.py:975
set_top(self)
Set Top.
Definition grid.py:961
get_position(self, x)
Get Position.
Definition grid.py:952
TimelineDataRange.
Definition grid.py:99
__init__(self, name="")
Initializer.
Definition grid.py:104
get_all(self)
Get all ranges.
Definition grid.py:140
get_ranges(self, start, end)
Get selected ranges.
Definition grid.py:147
add_range(self, range)
Add range.
Definition grid.py:132
get_ranges_bounds(self, start, end)
Get ranges bounds.
Definition grid.py:165
__search(self, key)
Search.
Definition grid.py:113
sort(self)
Sort ranges.
Definition grid.py:183
get_bounds(self)
Get bounds.
Definition grid.py:190
TimelineEvent class.
Definition grid.py:204
__search(self, key)
Search function.
Definition grid.py:217
get_events(self, start, end)
Get Events.
Definition grid.py:244
__init__(self, name="")
Get ranges bounds.
Definition grid.py:209
sort(self)
Sort function.
Definition grid.py:266
add_event(self, event)
Add Event.
Definition grid.py:236
get_bounds(self)
Get Bounds.
Definition grid.py:273
get_events_bounds(self, start, end)
Get Events Bounds.
Definition grid.py:255
Timeline class.
Definition grid.py:287
get_range(self, name)
Get range.
Definition grid.py:306
__init__(self, name="")
Initializer.
Definition grid.py:296
get_bounds(self)
Get Bounds.
Definition grid.py:378
event_int
event int
Definition grid.py:303
sort(self)
Sort the ranges and events.
Definition grid.py:366
get_events_str(self)
Get Events string.
Definition grid.py:352
get_event_str(self, name)
Get Event String.
Definition grid.py:319
get_ranges(self)
Get Ranges.
Definition grid.py:345
get_events_int(self)
Get Events int.
Definition grid.py:359
ranges
ranges
Definition grid.py:301
get_event_int(self, name)
Get Event Int.
Definition grid.py:332
event_str
event string
Definition grid.py:302
Timelines class.
Definition grid.py:407
__init__(self)
Definition grid.py:410
get_all(self)
Get All Timeline.
Definition grid.py:429
timelines
timelines
Definition grid.py:414
get_bounds(self)
Get Bounds.
Definition grid.py:444
get(self, name)
Get Timeline.
Definition grid.py:416
sort(self)
Sort the timelines.
Definition grid.py:436
get_all_range_values(self)
Get All Ranges.
Definition grid.py:459
TimelinesRenderer class.
Definition grid.py:651
right_width
right width
Definition grid.py:762
layout(self, width)
Get Data X Start.
Definition grid.py:717
grey_background
grey background
Definition grid.py:864
__init__(self)
Initializer.
Definition grid.py:674
draw_line(self, ctx, x, y, width, height)
Draw Line.
Definition grid.py:767
set_render_range(self, start, end)
Set Render Range.
Definition grid.py:698
timelines
timelines
Definition grid.py:695
get_data_x_start(self)
Get Data X Start.
Definition grid.py:708
get_height(self)
Get Height.
Definition grid.py:681
draw(self, ctx)
Draw.
Definition grid.py:847
max_text_height
maximum text height
Definition grid.py:763
draw_events(self, ctx, events, x, y, width, height)
Draw Event.
Definition grid.py:785
set_timelines(self, timelines, colors)
Set Timelines.
Definition grid.py:688
left_width
left width
Definition grid.py:761
draw_ranges(self, ctx, ranges, x, y, width, height)
Draw Ranges.
Definition grid.py:814
TopLegendRenderer class.
Definition grid.py:547
__init__(self)
Initializer.
Definition grid.py:558
set_legends(self, legends, colors)
Set padding.
Definition grid.py:572
set_padding(self, padding)
Set padding.
Definition grid.py:564
get_height(self)
Set padding.
Definition grid.py:609
draw(self, ctx)
Set padding.
Definition grid.py:616
layout(self, width)
Set padding.
Definition grid.py:582
events_cmp(a, b)
Definition grid.py:88
read_data(filename)
read_data function
Definition grid.py:1739
ranges_cmp(a, b)
Definition grid.py:78