A Discrete-Event Network Simulator
API
grid.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 import re
4 import sys
5 
6 import cairo
7 import gtk
8 
9 
10 
11 class DataRange:
12 
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.startstart = start
26  self.endend = end
27  self.valuevalue = value
28 
29 
30 
32 
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.atat = at
43  self.valuevalue = value
44 
45 
46 
47 class EventFloat:
48 
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.atat = at
59  self.valuevalue = value
60 
61 
62 
63 class EventInt:
64 
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.atat = at
75  self.valuevalue = value
76 
77 
78 def 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 
88 def 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 
100 
104  def __init__(self, name=""):
105  """! Initializer
106  @param self this object
107  @param name name
108  """
109  self.namename = name
110  self.rangesranges = []
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.rangesranges) - 1
121  while l <= u:
122  i = int((l + u) / 2)
123  if key >= self.rangesranges[i].start and key <= self.rangesranges[i].end:
124  return i
125  elif key < self.rangesranges[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.rangesranges.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.rangesranges
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__search(start)
155  e = self.__search__search(end)
156  if s == -1 and e == -1:
157  return []
158  elif s == -1:
159  return self.rangesranges[0 : e + 1]
160  elif e == -1:
161  return self.rangesranges[s : len(self.rangesranges)]
162  else:
163  return self.rangesranges[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__search(start)
173  e = self.__search__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.rangesranges))
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.rangesranges.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.rangesranges) > 0:
196  lo = self.rangesranges[0].start
197  hi = self.rangesranges[len(self.rangesranges) - 1].end
198  return (lo, hi)
199  else:
200  return (0, 0)
201 
202 
203 
205 
209  def __init__(self, name=""):
210  """! Get ranges bounds
211  @param self this object
212  @param name name
213  """
214  self.namename = name
215  self.eventsevents = []
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.eventsevents) - 1
225  while l <= u:
226  i = int((l + u) / 2)
227  if key == self.eventsevents[i].at:
228  return i
229  elif key < self.eventsevents[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.eventsevents.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__search(start)
252  e = self.__search__search(end)
253  return self.eventsevents[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__search(start)
263  e = self.__search__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.eventsevents.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.eventsevents) > 0:
279  lo = self.eventsevents[0].at
280  hi = self.eventsevents[-1].at
281  return (lo, hi)
282  else:
283  return (0, 0)
284 
285 
286 
287 class Timeline:
288 
296  def __init__(self, name=""):
297  """! Initializer
298  @param self this object
299  @param name name
300  """
301  self.rangesranges = []
302  self.event_strevent_str = []
303  self.event_intevent_int = []
304  self.namename = 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.rangesranges:
313  if range.name == name:
314  return range
315  timeline = TimelineDataRange(name)
316  self.rangesranges.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_strevent_str:
326  if event_str.name == name:
327  return event_str
328  timeline = TimelineEvent(name)
329  self.event_strevent_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_intevent_int:
339  if event_int.name == name:
340  return event_int
341  timeline = TimelineEvent(name)
342  self.event_intevent_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.rangesranges
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_strevent_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_intevent_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.rangesranges:
372  range.sort()
373  for event in self.event_intevent_int:
374  event.sort()
375  for event in self.event_strevent_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.rangesranges:
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_strevent_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_intevent_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 
407 class Timelines:
408 
410  def __init__(self):
411  """Initializer
412  @param self: this object
413  """
414  self.timelinestimelines = []
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.timelinestimelines:
423  if timeline.name == name:
424  return timeline
425  timeline = Timeline(name)
426  self.timelinestimelines.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.timelinestimelines
435 
436  def sort(self):
437  """! Sort the timelines
438  @param self this object
439  @return none
440  """
441  for timeline in self.timelinestimelines:
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.timelinestimelines:
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.timelinestimelines:
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 
473 class Color:
474 
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.rr = r
488  self.gg = g
489  self.bb = 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.rr = r
500  self.gg = g
501  self.bb = b
502 
503 
504 
505 class Colors:
506 
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__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__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__colors.has_key(name):
542  self.addadd(name, self.default_colorsdefault_colors.pop())
543  return self.__colors__colors.get(name)
544 
545 
546 
548 
558  def __init__(self):
559  """! Initializer
560  @param self this object
561  """
562  self.__padding__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 = 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 = legends
580  self.__colors__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 = width
589  surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 1, 1)
590  ctx = cairo.Context(surface)
591  line_height = 0
592  total_height = self.__padding__padding
593  line_used = self.__padding__padding
594  for legend in self.__legends__legends:
595  (t_width, t_height) = ctx.text_extents(legend)[2:4]
596  item_width = self.__padding__padding + self.__padding__padding + t_width + self.__padding__padding
597  item_height = t_height + self.__padding__padding
598  if item_height > line_height:
599  line_height = item_height
600  if line_used + item_width > self.__width__width:
601  line_used = self.__padding__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__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__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__padding
625  line_used = self.__padding__padding
626  for legend in self.__legends__legends:
627  (t_width, t_height) = ctx.text_extents(legend)[2:4]
628  item_width = self.__padding__padding + self.__padding__padding + t_width + self.__padding__padding
629  item_height = t_height + self.__padding__padding
630  if item_height > line_height:
631  line_height = item_height
632  if line_used + item_width > self.__width__width:
633  line_used = self.__padding__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__padding, self.__padding__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__colors[i].r, self.__colors__colors[i].g, self.__colors__colors[i].b)
643  ctx.fill()
644  ctx.move_to(x + self.__padding__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 
652 
674  def __init__(self):
675  """! Initializer
676  @param self this object
677  """
678  self.paddingpadding = 10
679  return
680 
681  def get_height(self):
682  """! Get Height
683  @param self this object
684  @return height
685  """
686  return self.heightheight
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.timelinestimelines = timelines
696  self.colorscolors = 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.startstart = start
706  self.endend = end
707 
708  def get_data_x_start(self):
709  """! Get Data X Start
710  @param self: this object
711  @return X start
712  """
713  return (
714  self.paddingpadding / 2 + self.left_widthleft_width + self.paddingpadding + self.right_widthright_width + self.paddingpadding / 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.timelinestimelines.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.paddingpadding
753  right_n_lines = range_n + eventint_n + eventstr_n
754  right_height = (right_n_lines - 1) * self.paddingpadding + 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.paddingpadding
757 
758  height = max(left_height, right_height)
759  height = max(height, right_data_height)
760 
761  self.left_widthleft_width = left_width
762  self.right_widthright_width = right_width
763  self.max_text_heightmax_text_height = max_text_height
764  self.widthwidth = width
765  self.heightheight = height + self.paddingpadding
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_backgroundgrey_background % 2) == 0:
797  ctx.rectangle(x, y - self.paddingpadding / 2, width, height + self.paddingpadding)
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.startstart, self.endend)
802  for event in events.events[lo:hi]:
803  real_x = int(x + (event.at - self.startstart) * width / (self.endend - self.startstart))
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_heightmax_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_backgroundgrey_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_backgroundgrey_background % 2) == 0:
826  ctx.rectangle(x, y - self.paddingpadding / 2, width, height + self.paddingpadding)
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.startstart, self.endend)
831  for data_range in ranges.ranges[lo:hi]:
832  s = max(data_range.start, self.startstart)
833  e = min(data_range.end, self.endend)
834  x_start = int(x + (s - self.startstart) * width / (self.endend - self.startstart))
835  x_end = int(x + (e - self.startstart) * width / (self.endend - self.startstart))
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.colorscolors.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_backgroundgrey_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.paddingpadding / 2
855  left_x_start = self.paddingpadding / 2
856  left_x_end = left_x_start + self.left_widthleft_width
857  right_x_start = left_x_end + self.paddingpadding
858  right_x_end = right_x_start + self.right_widthright_width
859  data_x_start = right_x_end + self.paddingpadding / 2
860  data_x_end = self.widthwidth
861  data_width = data_x_end - data_x_start
862  cur_y = top_y
863  self.draw_linedraw_line(ctx, 0, 0, self.widthwidth, 0)
864  self.grey_backgroundgrey_background = 1
865  for timeline in self.timelinestimelines.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_heightmax_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_heightmax_text_height - (t_height + y_bearing))
872  ctx.show_text(events_int.name)
873  self.draw_eventsdraw_events(
874  ctx, events_int, data_x_start, cur_y, data_width, self.max_text_heightmax_text_height + 5
875  )
876  cur_y += self.max_text_heightmax_text_height + 5 + self.paddingpadding
877  self.draw_linedraw_line(
878  ctx,
879  right_x_start - self.paddingpadding / 2,
880  cur_y - self.paddingpadding / 2,
881  self.right_widthright_width + self.paddingpadding,
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_heightmax_text_height - (t_height + y_bearing))
888  ctx.show_text(events_str.name)
889  self.draw_eventsdraw_events(
890  ctx, events_str, data_x_start, cur_y, data_width, self.max_text_heightmax_text_height + 5
891  )
892  cur_y += self.max_text_heightmax_text_height + 5 + self.paddingpadding
893  self.draw_linedraw_line(
894  ctx,
895  right_x_start - self.paddingpadding / 2,
896  cur_y - self.paddingpadding / 2,
897  self.right_widthright_width + self.paddingpadding,
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_heightmax_text_height - (t_height + y_bearing))
903  ctx.show_text(ranges.name)
904  self.draw_rangesdraw_ranges(ctx, ranges, data_x_start, cur_y, data_width, 10)
905  cur_y += self.max_text_heightmax_text_height + self.paddingpadding
906  self.draw_linedraw_line(
907  ctx,
908  right_x_start - self.paddingpadding / 2,
909  cur_y - self.paddingpadding / 2,
910  self.right_widthright_width + self.paddingpadding,
911  0,
912  )
913  self.draw_linedraw_line(ctx, 0, cur_y - self.paddingpadding / 2, self.widthwidth, 0)
914  bot_y = cur_y - self.paddingpadding / 2
915  self.draw_linedraw_line(ctx, left_x_end + self.paddingpadding / 2, 0, 0, bot_y)
916  self.draw_linedraw_line(ctx, right_x_end + self.paddingpadding / 2, 0, 0, bot_y)
917 
918 
919 
921 
935  def __init__(self):
936  """! Initializer
937  @param self this object
938  """
939  self.__top__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 = lo
950  self.__hi__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__lo) * self.__width__width / (self.__hi__hi - self.__lo__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__top = 1
967 
968  def set_bot(self):
969  """! Set Bottom
970  @param self this object
971  @return none
972  """
973  self.__top__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__hi - self.__lo__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__lo - (self.__lo__lo % delta) + delta
996  end = self.__hi__hi - (self.__hi__hi % delta)
997 
998  self.__delta__delta = delta
999  self.__width__width = width
1000 
1001  # calculate text height
1002  max_text_height = ctx.text_extents(
1003  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789"
1004  )[3]
1005  self.max_text_heightmax_text_height = max_text_height
1006  height = max_text_height + 10
1007  self.__height__height = height
1008 
1009  def get_height(self):
1010  """! Get Height
1011  @param self: this object
1012  @return height
1013  """
1014  return self.__height__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__delta
1023  start = self.__lo__lo - (self.__lo__lo % delta) + delta
1024  end = self.__hi__hi - (self.__hi__hi % delta)
1025 
1026  if self.__top__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__lo) * self.__width__width / (self.__hi__hi - self.__lo__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__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__lo - (self.__lo__lo % delta) + delta
1051  end = self.__hi__hi - (self.__hi__hi % delta)
1052  for x in range(int(start), int(end + delta), int(delta)):
1053  real_x = (x - self.__lo__lo) * self.__width__width / (self.__hi__hi - self.__lo__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 
1062 
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__start = float(start)
1091  self.__end__end = float(end)
1092  self.__mid_scale__mid_scale = ScaleRenderer()
1093  self.__mid_scale__mid_scale.set_top()
1094  self.__bot_scale__bot_scale = ScaleRenderer()
1095  self.__bot_scale__bot_scale.set_bounds(start, end)
1096  self.__bot_scale__bot_scale.set_bot()
1097  self.__width__width = 1
1098  self.__height__height = 1
1099 
1100  def get_width(self):
1101  """! Get Width
1102  @param self: this object
1103  @return width
1104  """
1105  return self.__width__width
1106 
1107  def get_height(self):
1108  """! Get Height
1109  @param self this object
1110  @return height
1111  """
1112  return self.__height__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__top_legend.get_height()
1121  x_start = self.__data__data.get_data_x_start()
1122  return (x_start, y_start, self.__width__width - x_start, self.__data__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__data.get_data_x_start()
1131  x_scaled = x / (self.__width__width - x_start) * (self.__r_end__r_end - self.__r_start__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 = (
1141  self.__top_legend__top_legend.get_height()
1142  + self.__data__data.get_height()
1143  + self.__mid_scale__mid_scale.get_height()
1144  + 20
1145  )
1146  y_height = self.__bot_scale__bot_scale.get_height() + 20
1147  x_start = self.__bot_scale__bot_scale.get_position(self.__r_start__r_start)
1148  x_end = self.__bot_scale__bot_scale.get_position(self.__r_end__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__width * (self.__end__end - self.__start__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__start, s)
1170  end = min(self.__end__end, e)
1171  self.__r_start__r_start = start
1172  self.__r_end__r_end = end
1173  self.__data__data.set_render_range(start, end)
1174  self.__mid_scale__mid_scale.set_bounds(start, end)
1175  self.layoutlayout(self.__width__width, self.__height__height)
1176 
1177  def get_range(self):
1178  """! Get Range
1179  @param self this object
1180  @return range
1181  """
1182  return (self.__r_start__r_start, self.__r_end__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 = 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 = 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 = width
1208  self.__height__height = height
1209  self.__top_legend__top_legend.layout(width)
1210  top_legend_height = self.__top_legend__top_legend.get_height()
1211  self.__data__data.layout(width)
1212  self.__mid_scale__mid_scale.layout(width - self.__data__data.get_data_x_start())
1213  self.__bot_scale__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__start) * width / (self.__end__end - self.__start__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__width, self.__height__height)
1237  ctx.fill()
1238 
1239  # top legend
1240  ctx.save()
1241  self.__top_legend__top_legend.draw(ctx)
1242  top_legend_height = self.__top_legend__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__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__data.draw(ctx)
1257  ctx.restore()
1258 
1259  # scale below data
1260  ctx.save()
1261  ctx.translate(
1262  self.__data__data.get_data_x_start(),
1263  top_legend_height + self.__data__data.get_height() + self.__mid_scale__mid_scale.get_height(),
1264  )
1265  self.__mid_scale__mid_scale.draw(ctx)
1266  ctx.restore()
1267 
1268  height_used = top_legend_height + self.__data__data.get_height() + self.__mid_scale__mid_scale.get_height()
1269 
1270  # separation between scale and left pane
1271  ctx.move_to(self.__data__data.get_data_x_start(), height_used)
1272  ctx.rel_line_to(0, -self.__mid_scale__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__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__bot_scale.get_position(self.__r_start__r_start)
1287  select_end = self.__bot_scale__bot_scale.get_position(self.__r_end__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__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__width, height_used)
1303  ctx.line_to(self.__width__width, height_used + 20)
1304  ctx.line_to(select_end, height_used + 20)
1305  ctx.line_to(self.__width__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__bot_scale.get_position(self.__r_start__r_start)
1316  unused_end = self.__bot_scale__bot_scale.get_position(self.__r_end__r_end)
1317  unused_height = self.__bot_scale__bot_scale.get_height() + 20
1318  ctx.rectangle(0, height_used, unused_start, unused_height)
1319  ctx.rectangle(unused_end, height_used, self.__width__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__width, height_used)
1326  ctx.line_to(self.__width__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__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__bot_scale.draw(ctx)
1357  ctx.restore()
1358 
1359 
1360 
1361 class GtkGraphicRenderer(gtk.DrawingArea):
1362 
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 = data
1409  self.__moving_left__moving_left = False
1410  self.__moving_right__moving_right = False
1411  self.__moving_both__moving_both = False
1412  self.__moving_top__moving_top = False
1413  self.__force_full_redraw__force_full_redraw = True
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 
1423  def set_smaller_zoom(self):
1424  """! Set Smaller Zoom
1425  @param self this object
1426  @return none
1427  """
1428  (start, end) = self.__data__data.get_range()
1429  self.__data__data.set_range(start, start + (end - start) * 2)
1430  self.__force_full_redraw__force_full_redraw = True
1431  self.queue_draw()
1432 
1433  def set_bigger_zoom(self):
1434  """! Set Bigger Zoom
1435  @param self this object
1436  @return none
1437  """
1438  (start, end) = self.__data__data.get_range()
1439  self.__data__data.set_range(start, start + (end - start) / 2)
1440  self.__force_full_redraw__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__data.get_width(), self.__data__data.get_height()
1451  )
1452  ctx = cairo.Context(self.__buffer_surface__buffer_surface)
1453  self.__data__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__data.get_selection_rectangle()
1464  (d_x, d_y, d_width, d_height) = self.__data__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__moving_left = True
1468  return True
1469  if abs(event.x - (x + width)) < 5:
1470  self.__moving_right__moving_right = True
1471  return True
1472  if event.x > x and event.x < x + width:
1473  self.__moving_both__moving_both = True
1474  self.__moving_both_start__moving_both_start = event.x
1475  self.__moving_both_cur__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__moving_top = True
1480  self.__moving_top_start__moving_top_start = event.x
1481  self.__moving_top_cur__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__moving_left:
1493  self.__moving_left__moving_left = False
1494  left = self.__data__data.scale_selection(self.__moving_left_cur__moving_left_cur)
1495  right = self.__data__data.get_range()[1]
1496  self.__data__data.set_range(left, right)
1497  self.__force_full_redraw__force_full_redraw = True
1498  self.queue_draw()
1499  return True
1500  if self.__moving_right__moving_right:
1501  self.__moving_right__moving_right = False
1502  right = self.__data__data.scale_selection(self.__moving_right_cur__moving_right_cur)
1503  left = self.__data__data.get_range()[0]
1504  self.__data__data.set_range(left, right)
1505  self.__force_full_redraw__force_full_redraw = True
1506  self.queue_draw()
1507  return True
1508  if self.__moving_both__moving_both:
1509  self.__moving_both__moving_both = False
1510  delta = self.__data__data.scale_selection(self.__moving_both_cur__moving_both_cur - self.__moving_both_start__moving_both_start)
1511  (left, right) = self.__data__data.get_range()
1512  self.__data__data.set_range(left + delta, right + delta)
1513  self.__force_full_redraw__force_full_redraw = True
1514  self.queue_draw()
1515  return True
1516  if self.__moving_top__moving_top:
1517  self.__moving_top__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__data.get_selection_rectangle()
1528  if self.__moving_left__moving_left:
1529  if event.x <= 0:
1530  self.__moving_left_cur__moving_left_cur = 0
1531  elif event.x >= x + width:
1532  self.__moving_left_cur__moving_left_cur = x + width
1533  else:
1534  self.__moving_left_cur__moving_left_cur = event.x
1535  self.queue_draw_area(0, int(y), int(self.__width__width), int(height))
1536  return True
1537  if self.__moving_right__moving_right:
1538  if event.x >= self.__width__width:
1539  self.__moving_right__moving_right = self.__width__width
1540  elif event.x < x:
1541  self.__moving_right_cur__moving_right_cur = x
1542  else:
1543  self.__moving_right_cur__moving_right_cur = event.x
1544  self.queue_draw_area(0, int(y), int(self.__width__width), int(height))
1545  return True
1546  if self.__moving_both__moving_both:
1547  cur_e = self.__width__width - (x + width - self.__moving_both_start__moving_both_start)
1548  cur_s = self.__moving_both_start__moving_both_start - x
1549  if event.x < cur_s:
1550  self.__moving_both_cur__moving_both_cur = cur_s
1551  elif event.x > cur_e:
1552  self.__moving_both_cur__moving_both_cur = cur_e
1553  else:
1554  self.__moving_both_cur__moving_both_cur = event.x
1555  self.queue_draw_area(0, int(y), int(self.__width__width), int(height))
1556  return True
1557  if self.__moving_top__moving_top:
1558  self.__moving_top_cur__moving_top_cur = event.x
1559  delta = self.__data__data.scale_data(self.__moving_top_start__moving_top_start - self.__moving_top_cur__moving_top_cur)
1560  (left, right) = self.__data__data.get_range()
1561  self.__data__data.set_range(left + delta, right + delta)
1562  self.__force_full_redraw__force_full_redraw = True
1563  self.__moving_top_start__moving_top_start = event.x
1564  self.queue_draw()
1565  return True
1566  (d_x, d_y, d_width, d_height) = self.__data__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__width = allocation.width
1589  self.__height__height = allocation.height
1590  self.__data__data.layout(allocation.width, allocation.height)
1591  self.__force_full_redraw__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__force_full_redraw:
1602  self.__buffer_surface__buffer_surface = cairo.ImageSurface(
1603  cairo.FORMAT_ARGB32, self.__data__data.get_width(), self.__data__data.get_height()
1604  )
1605  ctx = cairo.Context(self.__buffer_surface__buffer_surface)
1606  self.__data__data.draw(ctx)
1607  self.__force_full_redraw__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__buffer_surface)
1612  ctx.paint()
1613  (x, y, width, height) = self.__data__data.get_selection_rectangle()
1614  if self.__moving_left__moving_left:
1615  ctx.move_to(max(self.__moving_left_cur__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__moving_right:
1622  ctx.move_to(min(self.__moving_right_cur__moving_right_cur, self.__width__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__moving_both:
1629  delta_x = self.__moving_both_cur__moving_both_cur - self.__moving_both_start__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 
1645 
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 = window
1673  window.set_default_size(200, 200)
1674  vbox = gtk.VBox()
1675  window.add(vbox)
1676  render = GtkGraphicRenderer(graphic)
1677  self.__render__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__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__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__window, gtk.FILE_CHOOSER_ACTION_SAVE, ("Save", 1)
1719  )
1720  self.__dialog__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__dialog.get_filename()
1734  self.__render__render.output_png(filename)
1735  widget.hide()
1736 
1737 
1738 
1739 def 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 
1793 def 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 
1819 main()
#define min(a, b)
Definition: 80211b.c:41
#define max(a, b)
Definition: 80211b.c:42
Color class.
Definition: grid.py:473
def __init__(self, r=0.0, g=0.0, b=0.0)
Initializer.
Definition: grid.py:480
def set(self, r, g, b)
Set color.
Definition: grid.py:491
r
red
Definition: grid.py:487
g
green
Definition: grid.py:488
b
blue
Definition: grid.py:489
Colors class.
Definition: grid.py:505
def __init__(self)
Initializer.
Definition: grid.py:520
def lookup(self, name)
Lookup name.
Definition: grid.py:535
def add(self, name, color)
Add.
Definition: grid.py:526
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
def __init__(self, start=0, end=0, value="")
Initializer.
Definition: grid.py:18
EventFloat class.
Definition: grid.py:47
def __init__(self, at=0, value=0.0)
Initializer.
Definition: grid.py:52
value
value
Definition: grid.py:59
EventInt class.
Definition: grid.py:63
def __init__(self, at=0, value=0.0)
Initializer.
Definition: grid.py:68
value
value
Definition: grid.py:75
EventString class.
Definition: grid.py:31
def __init__(self, at=0, value="")
Initializer.
Definition: grid.py:36
value
value
Definition: grid.py:43
GraphicRenderer class.
Definition: grid.py:1061
__mid_scale
mid scale
Definition: grid.py:1092
def set_top_legend(self, top_legend)
Set Top Legend.
Definition: grid.py:1192
def get_range(self)
Get Range.
Definition: grid.py:1177
def draw(self, ctx)
Draw.
Definition: grid.py:1226
def get_selection_rectangle(self)
Get Selection Rectangle.
Definition: grid.py:1135
def set_range(self, start, end)
Set Range.
Definition: grid.py:1160
def get_height(self)
Get Height.
Definition: grid.py:1107
def get_data_rectangle(self)
Get Data Rectangle.
Definition: grid.py:1115
__bot_scale
bottom scale
Definition: grid.py:1094
def scale_selection(self, x)
Scale Selection.
Definition: grid.py:1151
__top_legend
top legend
Definition: grid.py:1198
def layout(self, width, height)
Set Layout.
Definition: grid.py:1200
def set_data(self, data)
Set Date.
Definition: grid.py:1184
def __x_pixel(self, x, width)
X Pixel.
Definition: grid.py:1216
def __init__(self, start, end)
Initializer.
Definition: grid.py:1084
def get_width(self)
Get Width.
Definition: grid.py:1100
def scale_data(self, x)
Get Data Rectangle.
Definition: grid.py:1124
GtkGraphicRenderer class.
Definition: grid.py:1361
__force_full_redraw
full redraw
Definition: grid.py:1413
__moving_top_start
moving top start
Definition: grid.py:1480
def set_smaller_zoom(self)
Set Smaller Zoom.
Definition: grid.py:1423
__moving_both_cur
moving both cur
Definition: grid.py:1475
def button_release(self, widget, event)
Button Release.
Definition: grid.py:1485
__moving_right
moving right
Definition: grid.py:1410
__moving_left
moving left
Definition: grid.py:1409
__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
def button_press(self, widget, event)
Button Press.
Definition: grid.py:1456
def size_allocate(self, widget, allocation)
Size Allocate.
Definition: grid.py:1581
__moving_top
moving top
Definition: grid.py:1412
__moving_both_start
moving both start
Definition: grid.py:1474
def motion_notify(self, widget, event)
Motion Notify.
Definition: grid.py:1520
def set_bigger_zoom(self)
Set Bigger Zoom.
Definition: grid.py:1433
__moving_both
moving both
Definition: grid.py:1411
def expose(self, widget, event)
Expose.
Definition: grid.py:1594
__moving_left_cur
moving left cur
Definition: grid.py:1530
def output_png(self, filename)
Output PNG.
Definition: grid.py:1443
def __init__(self, data)
Initializer.
Definition: grid.py:1402
MainWindow class.
Definition: grid.py:1644
def run(self, graphic)
Run function.
Definition: grid.py:1665
def __output_png_cb(self, widget)
Output PNG Callback.
Definition: grid.py:1711
def __init__(self)
Initializer.
Definition: grid.py:1659
def __set_smaller_cb(self, widget)
Set Smaller Callback.
Definition: grid.py:1695
def __dialog_response_cb(self, widget, response)
Dialog Response Callback.
Definition: grid.py:1725
__dialog
dialog
Definition: grid.py:1720
__window
window
Definition: grid.py:1672
def __set_bigger_cb(self, widget)
Set Bigger Callback.
Definition: grid.py:1703
__render
render
Definition: grid.py:1677
ScaleRenderer class.
Definition: grid.py:920
def layout(self, width)
Layout.
Definition: grid.py:975
def draw(self, ctx)
Draw.
Definition: grid.py:1016
max_text_height
maximum text height
Definition: grid.py:1005
def get_position(self, x)
Get Position.
Definition: grid.py:952
def set_bot(self)
Set Bottom.
Definition: grid.py:968
__height
height
Definition: grid.py:1007
def set_top(self)
Set Top.
Definition: grid.py:961
def __init__(self)
Initializer.
Definition: grid.py:935
def get_height(self)
Get Height.
Definition: grid.py:1009
def set_bounds(self, lo, hi)
Set Bounds.
Definition: grid.py:942
TimelineDataRange.
Definition: grid.py:99
def __init__(self, name="")
Initializer.
Definition: grid.py:104
def get_bounds(self)
Get bounds.
Definition: grid.py:190
def add_range(self, range)
Add range.
Definition: grid.py:132
def __search(self, key)
Search.
Definition: grid.py:113
def get_ranges_bounds(self, start, end)
Get ranges bounds.
Definition: grid.py:165
def get_ranges(self, start, end)
Get selected ranges.
Definition: grid.py:147
def sort(self)
Sort ranges.
Definition: grid.py:183
def get_all(self)
Get all ranges.
Definition: grid.py:140
TimelineEvent class.
Definition: grid.py:204
def add_event(self, event)
Add Event.
Definition: grid.py:236
def get_events(self, start, end)
Get Events.
Definition: grid.py:244
def get_events_bounds(self, start, end)
Get Events Bounds.
Definition: grid.py:255
def sort(self)
Sort function.
Definition: grid.py:266
def get_bounds(self)
Get Bounds.
Definition: grid.py:273
def __search(self, key)
Search function.
Definition: grid.py:217
def __init__(self, name="")
Get ranges bounds.
Definition: grid.py:209
events
events
Definition: grid.py:215
Timeline class.
Definition: grid.py:287
def get_ranges(self)
Get Ranges.
Definition: grid.py:345
def get_range(self, name)
Get range.
Definition: grid.py:306
def get_event_int(self, name)
Get Event Int.
Definition: grid.py:332
event_int
event int
Definition: grid.py:303
def get_events_int(self)
Get Events int.
Definition: grid.py:359
ranges
ranges
Definition: grid.py:301
def get_event_str(self, name)
Get Event String.
Definition: grid.py:319
def __init__(self, name="")
Initializer.
Definition: grid.py:296
event_str
event string
Definition: grid.py:302
def get_bounds(self)
Get Bounds.
Definition: grid.py:378
def get_events_str(self)
Get Events string.
Definition: grid.py:352
def sort(self)
Sort the ranges and events.
Definition: grid.py:366
name
name
Definition: grid.py:304
Timelines class.
Definition: grid.py:407
def get_bounds(self)
Get Bounds.
Definition: grid.py:444
def __init__(self)
Definition: grid.py:410
def get(self, name)
Get Timeline.
Definition: grid.py:416
timelines
timelines
Definition: grid.py:414
def get_all_range_values(self)
Get All Ranges.
Definition: grid.py:459
def get_all(self)
Get All Timeline.
Definition: grid.py:429
def sort(self)
Sort the timelines.
Definition: grid.py:436
TimelinesRenderer class.
Definition: grid.py:651
right_width
right width
Definition: grid.py:762
def set_timelines(self, timelines, colors)
Set Timelines.
Definition: grid.py:688
grey_background
grey background
Definition: grid.py:864
def draw_line(self, ctx, x, y, width, height)
Draw Line.
Definition: grid.py:767
def get_data_x_start(self)
Get Data X Start.
Definition: grid.py:708
def set_render_range(self, start, end)
Set Render Range.
Definition: grid.py:698
timelines
timelines
Definition: grid.py:695
def layout(self, width)
Get Data X Start.
Definition: grid.py:717
def draw(self, ctx)
Draw.
Definition: grid.py:847
max_text_height
maximum text height
Definition: grid.py:763
def draw_events(self, ctx, events, x, y, width, height)
Draw Event.
Definition: grid.py:785
def __init__(self)
Initializer.
Definition: grid.py:674
def get_height(self)
Get Height.
Definition: grid.py:681
def draw_ranges(self, ctx, ranges, x, y, width, height)
Draw Ranges.
Definition: grid.py:814
left_width
left width
Definition: grid.py:761
TopLegendRenderer class.
Definition: grid.py:547
def get_height(self)
Set padding.
Definition: grid.py:609
def layout(self, width)
Set padding.
Definition: grid.py:582
def __init__(self)
Initializer.
Definition: grid.py:558
def draw(self, ctx)
Set padding.
Definition: grid.py:616
def set_padding(self, padding)
Set padding.
Definition: grid.py:564
def set_legends(self, legends, colors)
Set padding.
Definition: grid.py:572
def ranges_cmp(a, b)
Definition: grid.py:78
def events_cmp(a, b)
Definition: grid.py:88
def read_data(filename)
read_data function
Definition: grid.py:1739
auto get(const nlohmann::detail::iteration_proxy_value< IteratorType > &i) -> decltype(i.key())
Definition: json.h:4023
def set_bounds(x1, y1, x2, y2)
Definition: core.py:1975