summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMac Mollison <mollison@cs.unc.edu>2010-03-20 17:40:00 -0400
committerMac Mollison <mollison@cs.unc.edu>2010-03-20 17:40:00 -0400
commit90d1825ad3ad20430734c1c75b899d14c4e6b700 (patch)
tree834a898b506f37a35c73d3845061ec8f7284394e
parent7fdb4dbbbca577efbeec47cd1364eb319346a0cc (diff)
Zapped a bunch of trailing whitespace
-rwxr-xr-xinstall.py4
-rw-r--r--unit_trace/naive_trace_reader.py12
-rw-r--r--unit_trace/progress.py2
-rw-r--r--unit_trace/sanitizer.py2
-rw-r--r--unit_trace/stats.py2
-rw-r--r--unit_trace/stdout_printer.py2
-rw-r--r--unit_trace/trace_reader.py16
-rw-r--r--unit_trace/viz/convert.py24
-rw-r--r--unit_trace/viz/draw.py628
-rw-r--r--unit_trace/viz/format.py30
-rw-r--r--unit_trace/viz/renderer.py16
-rw-r--r--unit_trace/viz/schedule.py252
-rw-r--r--unit_trace/viz/viewer.py218
-rwxr-xr-xunit_trace/viz/visualizer.py6
14 files changed, 607 insertions, 607 deletions
diff --git a/install.py b/install.py
index 935c7df..b06462c 100755
--- a/install.py
+++ b/install.py
@@ -4,8 +4,8 @@
4# Description 4# Description
5################################################################################ 5################################################################################
6 6
7# This script installes (or re-installs) the unit_trace Python module, so that 7# This script installes (or re-installs) the unit_trace Python module, so that
8# the unit_trace library can be imported with `import unit_trace` by a Python 8# the unit_trace library can be imported with `import unit_trace` by a Python
9# script, from anywhere on the system. 9# script, from anywhere on the system.
10 10
11# The installation merely consists of copying the unit_trace directory to 11# The installation merely consists of copying the unit_trace directory to
diff --git a/unit_trace/naive_trace_reader.py b/unit_trace/naive_trace_reader.py
index 0f117b8..0f45895 100644
--- a/unit_trace/naive_trace_reader.py
+++ b/unit_trace/naive_trace_reader.py
@@ -31,18 +31,18 @@ def trace_reader(files):
31 data = f.read(RECORD_HEAD_SIZE) 31 data = f.read(RECORD_HEAD_SIZE)
32 try: 32 try:
33 type_num = struct.unpack_from('b',data)[0] 33 type_num = struct.unpack_from('b',data)[0]
34 except struct.error: 34 except struct.error:
35 break #We read to the end of the file 35 break #We read to the end of the file
36 type = _get_type(type_num) 36 type = _get_type(type_num)
37 try: 37 try:
38 values = struct.unpack_from(StHeader.format + 38 values = struct.unpack_from(StHeader.format +
39 type.format,data) 39 type.format,data)
40 record_dict = dict(zip(type.keys,values)) 40 record_dict = dict(zip(type.keys,values))
41 except struct.error: 41 except struct.error:
42 f.close() 42 f.close()
43 print "Invalid record detected, stopping." 43 print "Invalid record detected, stopping."
44 exit() 44 exit()
45 45
46 # Convert the record_dict into an object 46 # Convert the record_dict into an object
47 record = _dict2obj(record_dict) 47 record = _dict2obj(record_dict)
48 48
@@ -69,7 +69,7 @@ def _dict2obj(d):
69 o = Obj() 69 o = Obj()
70 for key in d.keys(): 70 for key in d.keys():
71 o.__dict__[key] = d[key] 71 o.__dict__[key] = d[key]
72 return o 72 return o
73 73
74############################################################################### 74###############################################################################
75# Trace record data types and accessor functions 75# Trace record data types and accessor functions
@@ -95,7 +95,7 @@ class StNameData(object):
95 keys = StHeader.keys + ['name'] 95 keys = StHeader.keys + ['name']
96 message = 'The name of the executable of this process.' 96 message = 'The name of the executable of this process.'
97 97
98class StParamData(object): 98class StParamData(object):
99 format = 'IIIc' 99 format = 'IIIc'
100 formatStr = struct.Struct(StHeader.format + format) 100 formatStr = struct.Struct(StHeader.format + format)
101 keys = StHeader.keys + ['wcet','period','phase','partition'] 101 keys = StHeader.keys + ['wcet','period','phase','partition']
@@ -107,7 +107,7 @@ class StReleaseData(object):
107 keys = StHeader.keys + ['when','deadline'] 107 keys = StHeader.keys + ['when','deadline']
108 message = 'A job was/is going to be released.' 108 message = 'A job was/is going to be released.'
109 109
110#Not yet used by Sched Trace 110#Not yet used by Sched Trace
111class StAssignedData(object): 111class StAssignedData(object):
112 format = 'Qc' 112 format = 'Qc'
113 formatStr = struct.Struct(StHeader.format + format) 113 formatStr = struct.Struct(StHeader.format + format)
diff --git a/unit_trace/progress.py b/unit_trace/progress.py
index d987ecd..d0f0482 100644
--- a/unit_trace/progress.py
+++ b/unit_trace/progress.py
@@ -25,7 +25,7 @@ def progress(stream):
25 25
26 start_time = 0 26 start_time = 0
27 count = 0 27 count = 0
28 28
29 for record in stream: 29 for record in stream:
30 if record.record_type=="event": 30 if record.record_type=="event":
31 count += 1 31 count += 1
diff --git a/unit_trace/sanitizer.py b/unit_trace/sanitizer.py
index 79315cc..598379a 100644
--- a/unit_trace/sanitizer.py
+++ b/unit_trace/sanitizer.py
@@ -49,5 +49,5 @@ def sanitizer(stream):
49 if record.type_name == 'switch_away': 49 if record.type_name == 'switch_away':
50 if (record.pid,record.job) not in jobs_switched_to: 50 if (record.pid,record.job) not in jobs_switched_to:
51 record.job -= 1 51 record.job -= 1
52 52
53 yield record 53 yield record
diff --git a/unit_trace/stats.py b/unit_trace/stats.py
index 34a842f..17c5fc9 100644
--- a/unit_trace/stats.py
+++ b/unit_trace/stats.py
@@ -32,7 +32,7 @@ def stats(stream):
32 rec = Obj() 32 rec = Obj()
33 rec.record_type = "meta" 33 rec.record_type = "meta"
34 rec.type_name = "stats" 34 rec.type_name = "stats"
35 rec.num_inversions = num_inversions 35 rec.num_inversions = num_inversions
36 rec.min_inversion = min_inversion 36 rec.min_inversion = min_inversion
37 rec.max_inversion = max_inversion 37 rec.max_inversion = max_inversion
38 rec.avg_inversion = avg_inversion 38 rec.avg_inversion = avg_inversion
diff --git a/unit_trace/stdout_printer.py b/unit_trace/stdout_printer.py
index f8d9a84..8842b71 100644
--- a/unit_trace/stdout_printer.py
+++ b/unit_trace/stdout_printer.py
@@ -62,7 +62,7 @@ def _print_inversion_end(record):
62 print #newline 62 print #newline
63 63
64def _print_stats(record): 64def _print_stats(record):
65 print "Inversion statistics" 65 print "Inversion statistics"
66 print "Num inversions: %d" % (record.num_inversions) 66 print "Num inversions: %d" % (record.num_inversions)
67 print "Min inversion: %d" % (record.min_inversion) 67 print "Min inversion: %d" % (record.min_inversion)
68 print "Max inversion: %d" % (record.max_inversion) 68 print "Max inversion: %d" % (record.max_inversion)
diff --git a/unit_trace/trace_reader.py b/unit_trace/trace_reader.py
index 44a3c75..e1d2095 100644
--- a/unit_trace/trace_reader.py
+++ b/unit_trace/trace_reader.py
@@ -5,7 +5,7 @@
5# trace_reader(files) returns an iterator which produces records 5# trace_reader(files) returns an iterator which produces records
6# in order from the files given. (the param is a list of files.) 6# in order from the files given. (the param is a list of files.)
7# 7#
8# Each record is just a Python object. It is guaranteed to have the following 8# Each record is just a Python object. It is guaranteed to have the following
9# attributes: 9# attributes:
10# - 'pid': pid of the task 10# - 'pid': pid of the task
11# - 'job': job number for that task 11# - 'job': job number for that task
@@ -66,7 +66,7 @@ def trace_reader(files):
66 # overwhelmingly probably. 66 # overwhelmingly probably.
67 for x in range(0,len(file_iter_buff)): 67 for x in range(0,len(file_iter_buff)):
68 for y in range(0,100): 68 for y in range(0,100):
69 file_iter_buff[x].append(file_iters[x].next()) 69 file_iter_buff[x].append(file_iters[x].next())
70 for x in range(0,len(file_iter_buff)): 70 for x in range(0,len(file_iter_buff)):
71 file_iter_buff[x] = sorted(file_iter_buff[x],key=lambda rec: rec.when) 71 file_iter_buff[x] = sorted(file_iter_buff[x],key=lambda rec: rec.when)
72 72
@@ -110,7 +110,7 @@ def trace_reader(files):
110 last_time = earliest.when 110 last_time = earliest.when
111 111
112 # Yield the record 112 # Yield the record
113 yield earliest 113 yield earliest
114 114
115############################################################################### 115###############################################################################
116# Private functions 116# Private functions
@@ -123,11 +123,11 @@ def _get_file_iter(file):
123 data = f.read(RECORD_HEAD_SIZE) 123 data = f.read(RECORD_HEAD_SIZE)
124 try: 124 try:
125 type_num = struct.unpack_from('b',data)[0] 125 type_num = struct.unpack_from('b',data)[0]
126 except struct.error: 126 except struct.error:
127 break #We read to the end of the file 127 break #We read to the end of the file
128 type = _get_type(type_num) 128 type = _get_type(type_num)
129 try: 129 try:
130 values = struct.unpack_from(StHeader.format + 130 values = struct.unpack_from(StHeader.format +
131 type.format,data) 131 type.format,data)
132 record_dict = dict(zip(type.keys,values)) 132 record_dict = dict(zip(type.keys,values))
133 except struct.error: 133 except struct.error:
@@ -157,7 +157,7 @@ def _dict2obj(d):
157 o = Obj() 157 o = Obj()
158 for key in d.keys(): 158 for key in d.keys():
159 o.__dict__[key] = d[key] 159 o.__dict__[key] = d[key]
160 return o 160 return o
161 161
162############################################################################### 162###############################################################################
163# Trace record data types and accessor functions 163# Trace record data types and accessor functions
@@ -183,7 +183,7 @@ class StNameData:
183 keys = StHeader.keys + ['name'] 183 keys = StHeader.keys + ['name']
184 message = 'The name of the executable of this process.' 184 message = 'The name of the executable of this process.'
185 185
186class StParamData: 186class StParamData:
187 format = 'IIIc' 187 format = 'IIIc'
188 formatStr = struct.Struct(StHeader.format + format) 188 formatStr = struct.Struct(StHeader.format + format)
189 keys = StHeader.keys + ['wcet','period','phase','partition'] 189 keys = StHeader.keys + ['wcet','period','phase','partition']
@@ -195,7 +195,7 @@ class StReleaseData:
195 keys = StHeader.keys + ['when','deadline'] 195 keys = StHeader.keys + ['when','deadline']
196 message = 'A job was/is going to be released.' 196 message = 'A job was/is going to be released.'
197 197
198#Not yet used by Sched Trace 198#Not yet used by Sched Trace
199class StAssignedData: 199class StAssignedData:
200 format = 'Qc' 200 format = 'Qc'
201 formatStr = struct.Struct(StHeader.format + format) 201 formatStr = struct.Struct(StHeader.format + format)
diff --git a/unit_trace/viz/convert.py b/unit_trace/viz/convert.py
index a7aff8b..d19bc73 100644
--- a/unit_trace/viz/convert.py
+++ b/unit_trace/viz/convert.py
@@ -24,13 +24,13 @@ def _get_job_from_record(sched, record):
24 sched.get_tasks()[tname].add_job(Job(job_no, [])) 24 sched.get_tasks()[tname].add_job(Job(job_no, []))
25 job = sched.get_tasks()[tname].get_jobs()[job_no] 25 job = sched.get_tasks()[tname].get_jobs()[job_no]
26 return job 26 return job
27 27
28def convert_trace_to_schedule(stream): 28def convert_trace_to_schedule(stream):
29 """The main function of interest in this module. Coverts a stream of records 29 """The main function of interest in this module. Coverts a stream of records
30 to a Schedule object.""" 30 to a Schedule object."""
31 def noop(): 31 def noop():
32 pass 32 pass
33 33
34 num_cpus, stream = _find_num_cpus(stream) 34 num_cpus, stream = _find_num_cpus(stream)
35 sched = Schedule('sched', num_cpus) 35 sched = Schedule('sched', num_cpus)
36 for record in stream: 36 for record in stream:
@@ -41,10 +41,10 @@ def convert_trace_to_schedule(stream):
41 if record.record_type == 'event': 41 if record.record_type == 'event':
42 job = _get_job_from_record(sched, record) 42 job = _get_job_from_record(sched, record)
43 cpu = record.cpu 43 cpu = record.cpu
44 44
45 if not hasattr(record, 'deadline'): 45 if not hasattr(record, 'deadline'):
46 record.deadline = None 46 record.deadline = None
47 47
48 actions = { 48 actions = {
49 'name' : (noop), 49 'name' : (noop),
50 'params' : (noop), 50 'params' : (noop),
@@ -64,27 +64,27 @@ def convert_trace_to_schedule(stream):
64 job.add_event(ResumeEvent(record.when, cpu))), 64 job.add_event(ResumeEvent(record.when, cpu))),
65 'sys_release' : (noop) 65 'sys_release' : (noop)
66 } 66 }
67 67
68 actions[record.type_name]() 68 actions[record.type_name]()
69 69
70 elif record.record_type == 'error': 70 elif record.record_type == 'error':
71 job = _get_job_from_record(sched, record.job) 71 job = _get_job_from_record(sched, record.job)
72 72
73 actions = { 73 actions = {
74 'inversion_start' : (lambda : 74 'inversion_start' : (lambda :
75 job.add_event(InversionStartEvent(record.job.inversion_start))), 75 job.add_event(InversionStartEvent(record.job.inversion_start))),
76 'inversion_end' : (lambda : 76 'inversion_end' : (lambda :
77 job.add_event(InversionEndEvent(record.job.inversion_end))) 77 job.add_event(InversionEndEvent(record.job.inversion_end)))
78 } 78 }
79 79
80 actions[record.type_name]() 80 actions[record.type_name]()
81 81
82 return sched 82 return sched
83 83
84def _pid_to_task_name(pid): 84def _pid_to_task_name(pid):
85 """Converts a PID to an appropriate name for a task.""" 85 """Converts a PID to an appropriate name for a task."""
86 return str(pid) 86 return str(pid)
87 87
88def _find_num_cpus(stream): 88def _find_num_cpus(stream):
89 """Determines the number of CPUs used by scanning the binary format.""" 89 """Determines the number of CPUs used by scanning the binary format."""
90 max = 0 90 max = 0
@@ -94,7 +94,7 @@ def _find_num_cpus(stream):
94 if record.record_type == 'event': 94 if record.record_type == 'event':
95 if record.cpu > max: 95 if record.cpu > max:
96 max = record.cpu 96 max = record.cpu
97 97
98 def recycle(l): 98 def recycle(l):
99 for record in l: 99 for record in l:
100 yield record 100 yield record
diff --git a/unit_trace/viz/draw.py b/unit_trace/viz/draw.py
index 8c48744..dced27d 100644
--- a/unit_trace/viz/draw.py
+++ b/unit_trace/viz/draw.py
@@ -27,19 +27,19 @@ class Surface(object):
27 self.height = 0 27 self.height = 0
28 self.fname = fname 28 self.fname = fname
29 self.ctx = ctx 29 self.ctx = ctx
30 30
31 def renew(self, width, height): 31 def renew(self, width, height):
32 raise NotImplementedError 32 raise NotImplementedError
33 33
34 def change_ctx(self, ctx): 34 def change_ctx(self, ctx):
35 self.ctx = ctx 35 self.ctx = ctx
36 36
37 def get_fname(self): 37 def get_fname(self):
38 return self.fname 38 return self.fname
39 39
40 def write_out(self, fname): 40 def write_out(self, fname):
41 raise NotImplementedError 41 raise NotImplementedError
42 42
43 def pan(self, x, y, width, height): 43 def pan(self, x, y, width, height):
44 """A surface might actually represent just a ``window'' into 44 """A surface might actually represent just a ``window'' into
45 what we are drawing on. For instance, if we are scrolling through 45 what we are drawing on. For instance, if we are scrolling through
@@ -51,7 +51,7 @@ class Surface(object):
51 self.virt_y = y 51 self.virt_y = y
52 self.width = width 52 self.width = width
53 self.height = height 53 self.height = height
54 54
55 def get_real_coor(self, x, y): 55 def get_real_coor(self, x, y):
56 """Translates the coordinates (x, y) 56 """Translates the coordinates (x, y)
57 in the ``theoretical'' plane to the true (x, y) coordinates on this surface 57 in the ``theoretical'' plane to the true (x, y) coordinates on this surface
@@ -59,48 +59,48 @@ class Surface(object):
59 bounds of the surface, 59 bounds of the surface,
60 if we want something outside the surface's ``window''.""" 60 if we want something outside the surface's ``window''."""
61 return (x - self.virt_x, y - self.virt_y) 61 return (x - self.virt_x, y - self.virt_y)
62 62
63class SVGSurface(Surface): 63class SVGSurface(Surface):
64 def renew(self, width, height): 64 def renew(self, width, height):
65 iwidth = int(math.ceil(width)) 65 iwidth = int(math.ceil(width))
66 iheight = int(math.ceil(height)) 66 iheight = int(math.ceil(height))
67 self.surface = cairo.SVGSurface(self.fname, iwidth, iheight) 67 self.surface = cairo.SVGSurface(self.fname, iwidth, iheight)
68 self.ctx = cairo.Context(self.surface) 68 self.ctx = cairo.Context(self.surface)
69 69
70 def write_out(self, fname): 70 def write_out(self, fname):
71 os.execl('cp', self.fname, fname) 71 os.execl('cp', self.fname, fname)
72 72
73class ImageSurface(Surface): 73class ImageSurface(Surface):
74 def renew(self, width, height): 74 def renew(self, width, height):
75 iwidth = int(math.ceil(width)) 75 iwidth = int(math.ceil(width))
76 iheight = int(math.ceil(height)) 76 iheight = int(math.ceil(height))
77 self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, iwidth, iheight) 77 self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, iwidth, iheight)
78 self.ctx = cairo.Context(self.surface) 78 self.ctx = cairo.Context(self.surface)
79 79
80 def write_out(self, fname): 80 def write_out(self, fname):
81 if self.surface is None: 81 if self.surface is None:
82 raise ValueError('Don\'t own surface, can\'t write to to file') 82 raise ValueError('Don\'t own surface, can\'t write to to file')
83 83
84 self.surface.write_to_png(fname) 84 self.surface.write_to_png(fname)
85 85
86class Pattern(object): 86class Pattern(object):
87 DEF_STRIPE_SIZE = 10 87 DEF_STRIPE_SIZE = 10
88 MAX_FADE_WIDTH = 250 88 MAX_FADE_WIDTH = 250
89 89
90 def __init__(self, color_list, stripe_size=DEF_STRIPE_SIZE): 90 def __init__(self, color_list, stripe_size=DEF_STRIPE_SIZE):
91 self.color_list = color_list 91 self.color_list = color_list
92 self.stripe_size = stripe_size 92 self.stripe_size = stripe_size
93 93
94 def render_on_canvas(self, canvas, x, y, width, height, fade=False): 94 def render_on_canvas(self, canvas, x, y, width, height, fade=False):
95 fade_span = min(width, Pattern.MAX_FADE_WIDTH) 95 fade_span = min(width, Pattern.MAX_FADE_WIDTH)
96 96
97 if len(self.color_list) == 1: 97 if len(self.color_list) == 1:
98 if fade: 98 if fade:
99 canvas.fill_rect_fade(x, y, fade_span, height, (1.0, 1.0, 1.0), \ 99 canvas.fill_rect_fade(x, y, fade_span, height, (1.0, 1.0, 1.0), \
100 self.color_list[0]) 100 self.color_list[0])
101 else: 101 else:
102 canvas.fill_rect(x, y, width, height, self.color_list[0]) 102 canvas.fill_rect(x, y, width, height, self.color_list[0])
103 103
104 if width > Pattern.MAX_FADE_WIDTH: 104 if width > Pattern.MAX_FADE_WIDTH:
105 canvas.fill_rect(x + Pattern.MAX_FADE_WIDTH, y, width - Pattern.MAX_FADE_WIDTH, 105 canvas.fill_rect(x + Pattern.MAX_FADE_WIDTH, y, width - Pattern.MAX_FADE_WIDTH,
106 height, self.color_list[0]) 106 height, self.color_list[0])
@@ -114,89 +114,89 @@ class Pattern(object):
114 min(self.stripe_size, bottom - y), (1.0, 1.0, 1.0), self.color_list[i]) 114 min(self.stripe_size, bottom - y), (1.0, 1.0, 1.0), self.color_list[i])
115 else: 115 else:
116 canvas.fill_rect(x, y, width, min(self.stripe_size, bottom - y), self.color_list[i]) 116 canvas.fill_rect(x, y, width, min(self.stripe_size, bottom - y), self.color_list[i])
117 117
118 if width > Pattern.MAX_FADE_WIDTH: 118 if width > Pattern.MAX_FADE_WIDTH:
119 canvas.fill_rect(x + Pattern.MAX_FADE_WIDTH, y, width - Pattern.MAX_FADE_WIDTH, 119 canvas.fill_rect(x + Pattern.MAX_FADE_WIDTH, y, width - Pattern.MAX_FADE_WIDTH,
120 min(self.stripe_size, bottom - y), self.color_list[i]) 120 min(self.stripe_size, bottom - y), self.color_list[i])
121 121
122 y += self.stripe_size 122 y += self.stripe_size
123 n += 1 123 n += 1
124 124
125class Canvas(object): 125class Canvas(object):
126 """This is a basic class that stores and draws on a Cairo surface, 126 """This is a basic class that stores and draws on a Cairo surface,
127 using various primitives related to drawing a real-time graph (up-arrows, 127 using various primitives related to drawing a real-time graph (up-arrows,
128 down-arrows, bars, ...). 128 down-arrows, bars, ...).
129 129
130 This is the lowest-level representation (aside perhaps from the Cairo 130 This is the lowest-level representation (aside perhaps from the Cairo
131 surface itself) of a real-time graph. It allows the user to draw 131 surface itself) of a real-time graph. It allows the user to draw
132 primitives at certain locations, but for the most part does not know 132 primitives at certain locations, but for the most part does not know
133 anything about real-time scheduling, just how to draw the basic parts 133 anything about real-time scheduling, just how to draw the basic parts
134 that make up a schedule graph. For that, see Graph or its descendants.""" 134 that make up a schedule graph. For that, see Graph or its descendants."""
135 135
136 BOTTOM_LAYER = 0 136 BOTTOM_LAYER = 0
137 MIDDLE_LAYER = 1 137 MIDDLE_LAYER = 1
138 TOP_LAYER = 2 138 TOP_LAYER = 2
139 139
140 LAYERS = (BOTTOM_LAYER, MIDDLE_LAYER, TOP_LAYER) 140 LAYERS = (BOTTOM_LAYER, MIDDLE_LAYER, TOP_LAYER)
141 141
142 NULL_PATTERN = -1 142 NULL_PATTERN = -1
143 143
144 SQRT3 = math.sqrt(3.0) 144 SQRT3 = math.sqrt(3.0)
145 145
146 def __init__(self, width, height, item_clist, bar_plist, surface): 146 def __init__(self, width, height, item_clist, bar_plist, surface):
147 """Creates a new Canvas of dimensions (width, height). The 147 """Creates a new Canvas of dimensions (width, height). The
148 parameters ``item_plist'' and ``bar_plist'' each specify a list 148 parameters ``item_plist'' and ``bar_plist'' each specify a list
149 of patterns to choose from when drawing the items on the y-axis 149 of patterns to choose from when drawing the items on the y-axis
150 or filling in bars, respectively.""" 150 or filling in bars, respectively."""
151 151
152 self.surface = surface 152 self.surface = surface
153 153
154 self.width = int(math.ceil(width)) 154 self.width = int(math.ceil(width))
155 self.height = int(math.ceil(height)) 155 self.height = int(math.ceil(height))
156 self.item_clist = item_clist 156 self.item_clist = item_clist
157 self.bar_plist = bar_plist 157 self.bar_plist = bar_plist
158 158
159 self.selectable_regions = {} 159 self.selectable_regions = {}
160 160
161 self.scale = 1.0 161 self.scale = 1.0
162 162
163 # clears the canvas. 163 # clears the canvas.
164 def clear(self): 164 def clear(self):
165 raise NotImplementedError 165 raise NotImplementedError
166 166
167 def scaled(self, *coors): 167 def scaled(self, *coors):
168 return [coor * self.scale for coor in coors] 168 return [coor * self.scale for coor in coors]
169 169
170 def draw_rect(self, x, y, width, height, color, thickness, snap=True): 170 def draw_rect(self, x, y, width, height, color, thickness, snap=True):
171 """Draws a rectangle somewhere (border only).""" 171 """Draws a rectangle somewhere (border only)."""
172 raise NotImplementedError 172 raise NotImplementedError
173 173
174 def fill_rect(self, x, y, width, height, color, snap=True): 174 def fill_rect(self, x, y, width, height, color, snap=True):
175 """Draws a filled rectangle somewhere. ``color'' is a 3-tuple.""" 175 """Draws a filled rectangle somewhere. ``color'' is a 3-tuple."""
176 raise NotImplementedError 176 raise NotImplementedError
177 177
178 def fill_rect_fade(self, x, y, width, height, lcolor, rcolor, snap=True): 178 def fill_rect_fade(self, x, y, width, height, lcolor, rcolor, snap=True):
179 """Draws a rectangle somewhere, filled in with the fade.""" 179 """Draws a rectangle somewhere, filled in with the fade."""
180 raise NotImplementedError 180 raise NotImplementedError
181 181
182 def draw_line(self, p0, p1, color, thickness, snap=True): 182 def draw_line(self, p0, p1, color, thickness, snap=True):
183 """Draws a line from p0 to p1 with a certain color and thickness.""" 183 """Draws a line from p0 to p1 with a certain color and thickness."""
184 raise NotImplementedError 184 raise NotImplementedError
185 185
186 def draw_polyline(self, coor_list, color, thickness, snap=True): 186 def draw_polyline(self, coor_list, color, thickness, snap=True):
187 """Draws a polyline, where coor_list = [(x_0, y_0), (x_1, y_1), ... (x_m, y_m)] 187 """Draws a polyline, where coor_list = [(x_0, y_0), (x_1, y_1), ... (x_m, y_m)]
188 specifies a polyline from (x_0, y_0) to (x_1, y_1), etc.""" 188 specifies a polyline from (x_0, y_0) to (x_1, y_1), etc."""
189 raise NotImplementedError 189 raise NotImplementedError
190 190
191 def fill_polyline(self, coor_list, color, thickness, snap=True): 191 def fill_polyline(self, coor_list, color, thickness, snap=True):
192 """Draws a polyline (probably a polygon) and fills it.""" 192 """Draws a polyline (probably a polygon) and fills it."""
193 raise NotImplementedError 193 raise NotImplementedError
194 194
195 def draw_label(self, text, x, y, fopts=GraphFormat.DEF_FOPTS_LABEL, 195 def draw_label(self, text, x, y, fopts=GraphFormat.DEF_FOPTS_LABEL,
196 halign=AlignMode.LEFT, valign=AlignMode.BOTTOM, snap=True): 196 halign=AlignMode.LEFT, valign=AlignMode.BOTTOM, snap=True):
197 """Draws text at a position with a certain alignment.""" 197 """Draws text at a position with a certain alignment."""
198 raise NotImplementedError 198 raise NotImplementedError
199 199
200 def draw_label_with_sscripts(self, text, supscript, subscript, x, y, \ 200 def draw_label_with_sscripts(self, text, supscript, subscript, x, y, \
201 textfopts=GraphFormat.DEF_FOPTS_LABEL, 201 textfopts=GraphFormat.DEF_FOPTS_LABEL,
202 sscriptfopts=GraphFormat.DEF_FOPTS_LABEL_SSCRIPT, \ 202 sscriptfopts=GraphFormat.DEF_FOPTS_LABEL_SSCRIPT, \
@@ -204,31 +204,31 @@ class Canvas(object):
204 """Draws text at a position with a certain alignment, along with optionally a superscript and 204 """Draws text at a position with a certain alignment, along with optionally a superscript and
205 subscript (which are None if either is not used.)""" 205 subscript (which are None if either is not used.)"""
206 raise NotImplementedError 206 raise NotImplementedError
207 207
208 def draw_y_axis(self, x, y, height): 208 def draw_y_axis(self, x, y, height):
209 """Draws the y-axis, starting from the bottom at the point x, y.""" 209 """Draws the y-axis, starting from the bottom at the point x, y."""
210 self.surface.ctx.set_source_rgb(0.0, 0.0, 0.0) 210 self.surface.ctx.set_source_rgb(0.0, 0.0, 0.0)
211 211
212 self.draw_line((x, y), (x, y - height), (0.0, 0.0, 0.0), GraphFormat.AXIS_THICKNESS) 212 self.draw_line((x, y), (x, y - height), (0.0, 0.0, 0.0), GraphFormat.AXIS_THICKNESS)
213 213
214 def draw_y_axis_labels(self, x, y, height, item_list, item_size, fopts=None): 214 def draw_y_axis_labels(self, x, y, height, item_list, item_size, fopts=None):
215 """Draws the item labels on the y-axis. ``item_list'' is the list 215 """Draws the item labels on the y-axis. ``item_list'' is the list
216 of strings to print, while item_size gives the vertical amount of 216 of strings to print, while item_size gives the vertical amount of
217 space that each item shall take up, in pixels.""" 217 space that each item shall take up, in pixels."""
218 if fopts is None: 218 if fopts is None:
219 fopts = GraphFormat.DEF_FOPTS_ITEM 219 fopts = GraphFormat.DEF_FOPTS_ITEM
220 220
221 x -= GraphFormat.Y_AXIS_ITEM_GAP 221 x -= GraphFormat.Y_AXIS_ITEM_GAP
222 y -= height - item_size / 2.0 222 y -= height - item_size / 2.0
223 223
224 orig_color = fopts.color 224 orig_color = fopts.color
225 for ctr, item in enumerate(item_list): 225 for ctr, item in enumerate(item_list):
226 fopts.color = self.get_item_color(ctr) 226 fopts.color = self.get_item_color(ctr)
227 self.draw_label(item, x, y, fopts, AlignMode.RIGHT, AlignMode.CENTER) 227 self.draw_label(item, x, y, fopts, AlignMode.RIGHT, AlignMode.CENTER)
228 y += item_size 228 y += item_size
229 229
230 fopts.color = orig_color 230 fopts.color = orig_color
231 231
232 def draw_x_axis(self, x, y, start_tick, end_tick, maj_sep, min_per_maj): 232 def draw_x_axis(self, x, y, start_tick, end_tick, maj_sep, min_per_maj):
233 """Draws the x-axis, including all the major and minor ticks (but not the labels). 233 """Draws the x-axis, including all the major and minor ticks (but not the labels).
234 ``num_maj'' gives the number of major ticks, ``maj_sep'' the number of pixels between 234 ``num_maj'' gives the number of major ticks, ``maj_sep'' the number of pixels between
@@ -241,48 +241,48 @@ class Canvas(object):
241 for i in range(start_tick, end_tick + 1): 241 for i in range(start_tick, end_tick + 1):
242 self.draw_line((x, y), (x, y + GraphFormat.MAJ_TICK_SIZE), 242 self.draw_line((x, y), (x, y + GraphFormat.MAJ_TICK_SIZE),
243 (0.0, 0.0, 0.0), GraphFormat.AXIS_THICKNESS) 243 (0.0, 0.0, 0.0), GraphFormat.AXIS_THICKNESS)
244 244
245 if (i < end_tick): 245 if (i < end_tick):
246 for j in range(0, min_per_maj): 246 for j in range(0, min_per_maj):
247 self.draw_line((x, y), (x + maj_sep / min_per_maj, y), 247 self.draw_line((x, y), (x + maj_sep / min_per_maj, y),
248 (0.0, 0.0, 0.0), GraphFormat.AXIS_THICKNESS) 248 (0.0, 0.0, 0.0), GraphFormat.AXIS_THICKNESS)
249 249
250 x += 1.0 * maj_sep / min_per_maj 250 x += 1.0 * maj_sep / min_per_maj
251 if j < min_per_maj - 1: 251 if j < min_per_maj - 1:
252 self.draw_line((x, y), (x, y + GraphFormat.MIN_TICK_SIZE), 252 self.draw_line((x, y), (x, y + GraphFormat.MIN_TICK_SIZE),
253 (0.0, 0.0, 0.0), GraphFormat.AXIS_THICKNESS) 253 (0.0, 0.0, 0.0), GraphFormat.AXIS_THICKNESS)
254 254
255 def draw_x_axis_labels(self, x, y, start_tick, end_tick, maj_sep, min_per_maj, start=0, incr=1, show_min=False, \ 255 def draw_x_axis_labels(self, x, y, start_tick, end_tick, maj_sep, min_per_maj, start=0, incr=1, show_min=False, \
256 majfopts=GraphFormat.DEF_FOPTS_MAJ, minfopts=GraphFormat.DEF_FOPTS_MIN): 256 majfopts=GraphFormat.DEF_FOPTS_MAJ, minfopts=GraphFormat.DEF_FOPTS_MIN):
257 """Draws the labels for the x-axis. (x, y) should give the origin. 257 """Draws the labels for the x-axis. (x, y) should give the origin.
258 how far down you want the text. ``incr'' gives the increment per major 258 how far down you want the text. ``incr'' gives the increment per major
259 tick. ``start'' gives the value of the first tick. ``show_min'' specifies 259 tick. ``start'' gives the value of the first tick. ``show_min'' specifies
260 whether to draw labels at minor ticks.""" 260 whether to draw labels at minor ticks."""
261 261
262 x += GraphFormat.X_AXIS_MEASURE_OFS + start_tick * maj_sep 262 x += GraphFormat.X_AXIS_MEASURE_OFS + start_tick * maj_sep
263 y += GraphFormat.X_AXIS_LABEL_GAP + GraphFormat.MAJ_TICK_SIZE 263 y += GraphFormat.X_AXIS_LABEL_GAP + GraphFormat.MAJ_TICK_SIZE
264 264
265 minincr = incr / (min_per_maj * 1.0) 265 minincr = incr / (min_per_maj * 1.0)
266 266
267 cur = start * 1.0 267 cur = start * 1.0
268 268
269 for i in range(start_tick, end_tick + 1): 269 for i in range(start_tick, end_tick + 1):
270 text = util.format_float(cur, 2) 270 text = util.format_float(cur, 2)
271 self.draw_label(text, x, y, majfopts, AlignMode.CENTER, AlignMode.TOP) 271 self.draw_label(text, x, y, majfopts, AlignMode.CENTER, AlignMode.TOP)
272 272
273 if (i < end_tick): 273 if (i < end_tick):
274 if show_min: 274 if show_min:
275 for j in range(0, min_per_maj): 275 for j in range(0, min_per_maj):
276 x += 1.0 * maj_sep / min_per_maj 276 x += 1.0 * maj_sep / min_per_maj
277 cur += minincr 277 cur += minincr
278 text = util.format_float(cur, 2) 278 text = util.format_float(cur, 2)
279 279
280 if j < min_per_maj - 1: 280 if j < min_per_maj - 1:
281 self.draw_label(text, x, y, minfopts, AlignMode.CENTER, AlignMode.TOP) 281 self.draw_label(text, x, y, minfopts, AlignMode.CENTER, AlignMode.TOP)
282 else: 282 else:
283 x += maj_sep 283 x += maj_sep
284 cur += incr 284 cur += incr
285 285
286 def draw_grid(self, x, y, height, start_tick, end_tick, start_item, end_item, maj_sep, item_size, \ 286 def draw_grid(self, x, y, height, start_tick, end_tick, start_item, end_item, maj_sep, item_size, \
287 min_per_maj=None, show_min=False): 287 min_per_maj=None, show_min=False):
288 """Draws a grid dividing along the item boundaries and the major ticks. 288 """Draws a grid dividing along the item boundaries and the major ticks.
@@ -291,22 +291,22 @@ class Canvas(object):
291 ``start_item'' and ``end_item'' give the item boundaries to start and end drawing horizontal lines.""" 291 ``start_item'' and ``end_item'' give the item boundaries to start and end drawing horizontal lines."""
292 if start_tick > end_tick or start_item > end_item: 292 if start_tick > end_tick or start_item > end_item:
293 return 293 return
294 294
295 line_width = (end_tick - start_tick) * maj_sep 295 line_width = (end_tick - start_tick) * maj_sep
296 line_height = (end_item - start_item) * item_size 296 line_height = (end_item - start_item) * item_size
297 297
298 origin = (x, y) 298 origin = (x, y)
299 299
300 # draw horizontal lines first 300 # draw horizontal lines first
301 x = origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + start_tick * maj_sep 301 x = origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + start_tick * maj_sep
302 y = origin[1] - height + start_item * item_size 302 y = origin[1] - height + start_item * item_size
303 for i in range(start_item, end_item + 1): 303 for i in range(start_item, end_item + 1):
304 self.draw_line((x, y), (x + line_width, y), GraphFormat.GRID_COLOR, GraphFormat.GRID_THICKNESS) 304 self.draw_line((x, y), (x + line_width, y), GraphFormat.GRID_COLOR, GraphFormat.GRID_THICKNESS)
305 y += item_size 305 y += item_size
306 306
307 x = origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + start_tick * maj_sep 307 x = origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + start_tick * maj_sep
308 y = origin[1] - height + start_item * item_size 308 y = origin[1] - height + start_item * item_size
309 309
310 if show_min: 310 if show_min:
311 for i in range(0, (end_tick - start_tick) * min_per_maj + 1): 311 for i in range(0, (end_tick - start_tick) * min_per_maj + 1):
312 self.draw_line((x, y), (x, y + line_height), GraphFormat.GRID_COLOR, GraphFormat.GRID_THICKNESS) 312 self.draw_line((x, y), (x, y + line_height), GraphFormat.GRID_COLOR, GraphFormat.GRID_THICKNESS)
@@ -315,7 +315,7 @@ class Canvas(object):
315 for i in range(start_tick, end_tick + 1): 315 for i in range(start_tick, end_tick + 1):
316 self.draw_line((x, y), (x, y + line_height), GraphFormat.GRID_COLOR, GraphFormat.GRID_THICKNESS) 316 self.draw_line((x, y), (x, y + line_height), GraphFormat.GRID_COLOR, GraphFormat.GRID_THICKNESS)
317 x += maj_sep 317 x += maj_sep
318 318
319 def _draw_bar_border_common(self, x, y, width, height, color, thickness, clip_side): 319 def _draw_bar_border_common(self, x, y, width, height, color, thickness, clip_side):
320 if clip_side is None: 320 if clip_side is None:
321 self.draw_rect(x, y, width, height, color, thickness) 321 self.draw_rect(x, y, width, height, color, thickness)
@@ -325,213 +325,213 @@ class Canvas(object):
325 elif clip_side == AlignMode.RIGHT: 325 elif clip_side == AlignMode.RIGHT:
326 self.draw_polyline([(x + width, y), (x, y), (x, y + height), (x + width, y + height)], 326 self.draw_polyline([(x + width, y), (x, y), (x, y + height), (x + width, y + height)],
327 color, thickness) 327 color, thickness)
328 328
329 def draw_bar(self, x, y, width, height, n, clip_side, selected): 329 def draw_bar(self, x, y, width, height, n, clip_side, selected):
330 """Draws a bar with a certain set of dimensions, using pattern ``n'' from the 330 """Draws a bar with a certain set of dimensions, using pattern ``n'' from the
331 bar pattern list.""" 331 bar pattern list."""
332 332
333 color, thickness = {False : (GraphFormat.BORDER_COLOR, GraphFormat.BORDER_THICKNESS), 333 color, thickness = {False : (GraphFormat.BORDER_COLOR, GraphFormat.BORDER_THICKNESS),
334 True : (GraphFormat.HIGHLIGHT_COLOR, GraphFormat.BORDER_THICKNESS * 2.0)}[selected] 334 True : (GraphFormat.HIGHLIGHT_COLOR, GraphFormat.BORDER_THICKNESS * 2.0)}[selected]
335 335
336 # use a pattern to be pretty 336 # use a pattern to be pretty
337 self.get_bar_pattern(n).render_on_canvas(self, x, y, width, height, True) 337 self.get_bar_pattern(n).render_on_canvas(self, x, y, width, height, True)
338 338
339 self._draw_bar_border_common(x, y, width, height, color, thickness, clip_side) 339 self._draw_bar_border_common(x, y, width, height, color, thickness, clip_side)
340 340
341 def add_sel_bar(self, x, y, width, height, event): 341 def add_sel_bar(self, x, y, width, height, event):
342 self.add_sel_region(SelectableRegion(x, y, width, height, event)) 342 self.add_sel_region(SelectableRegion(x, y, width, height, event))
343 343
344 def draw_mini_bar(self, x, y, width, height, n, clip_side, selected): 344 def draw_mini_bar(self, x, y, width, height, n, clip_side, selected):
345 """Like the above, except it draws a miniature version. This is usually used for 345 """Like the above, except it draws a miniature version. This is usually used for
346 secondary purposes (i.e. to show jobs that _should_ have been running at a certain time). 346 secondary purposes (i.e. to show jobs that _should_ have been running at a certain time).
347 347
348 Of course we don't enforce the fact that this is mini, since the user can pass in width 348 Of course we don't enforce the fact that this is mini, since the user can pass in width
349 and height (but the mini bars do look slightly different: namely the borders are a different 349 and height (but the mini bars do look slightly different: namely the borders are a different
350 color)""" 350 color)"""
351 351
352 color, thickness = {False : (GraphFormat.LITE_BORDER_COLOR, GraphFormat.BORDER_THICKNESS), 352 color, thickness = {False : (GraphFormat.LITE_BORDER_COLOR, GraphFormat.BORDER_THICKNESS),
353 True : (GraphFormat.HIGHLIGHT_COLOR, GraphFormat.BORDER_THICKNESS * 1.5)}[selected] 353 True : (GraphFormat.HIGHLIGHT_COLOR, GraphFormat.BORDER_THICKNESS * 1.5)}[selected]
354 354
355 self.get_bar_pattern(n).render_on_canvas(self, x, y, width, height, True) 355 self.get_bar_pattern(n).render_on_canvas(self, x, y, width, height, True)
356 356
357 self._draw_bar_border_common(x, y, width, height, color, thickness, clip_side) 357 self._draw_bar_border_common(x, y, width, height, color, thickness, clip_side)
358 358
359 def add_sel_mini_bar(self, x, y, width, height, event): 359 def add_sel_mini_bar(self, x, y, width, height, event):
360 self.add_sel_region(SelectableRegion(x, y, width, height, event)) 360 self.add_sel_region(SelectableRegion(x, y, width, height, event))
361 361
362 def draw_completion_marker(self, x, y, height, selected): 362 def draw_completion_marker(self, x, y, height, selected):
363 """Draws the symbol that represents a job completion, using a certain height.""" 363 """Draws the symbol that represents a job completion, using a certain height."""
364 364
365 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected] 365 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected]
366 self.draw_line((x - height * GraphFormat.TEE_FACTOR / 2.0, y), 366 self.draw_line((x - height * GraphFormat.TEE_FACTOR / 2.0, y),
367 (x + height * GraphFormat.TEE_FACTOR / 2.0, y), 367 (x + height * GraphFormat.TEE_FACTOR / 2.0, y),
368 color, GraphFormat.BORDER_THICKNESS) 368 color, GraphFormat.BORDER_THICKNESS)
369 self.draw_line((x, y), (x, y + height), color, GraphFormat.BORDER_THICKNESS) 369 self.draw_line((x, y), (x, y + height), color, GraphFormat.BORDER_THICKNESS)
370 370
371 def add_sel_completion_marker(self, x, y, height, event): 371 def add_sel_completion_marker(self, x, y, height, event):
372 self.add_sel_region(SelectableRegion(x - height * GraphFormat.TEE_FACTOR / 2.0, y, 372 self.add_sel_region(SelectableRegion(x - height * GraphFormat.TEE_FACTOR / 2.0, y,
373 height * GraphFormat.TEE_FACTOR, height, event)) 373 height * GraphFormat.TEE_FACTOR, height, event))
374 374
375 def draw_release_arrow_big(self, x, y, height, selected): 375 def draw_release_arrow_big(self, x, y, height, selected):
376 """Draws a release arrow of a certain height: (x, y) should give the top 376 """Draws a release arrow of a certain height: (x, y) should give the top
377 (northernmost point) of the arrow. The height includes the arrowhead.""" 377 (northernmost point) of the arrow. The height includes the arrowhead."""
378 big_arrowhead_height = GraphFormat.BIG_ARROWHEAD_FACTOR * height 378 big_arrowhead_height = GraphFormat.BIG_ARROWHEAD_FACTOR * height
379 379
380 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected] 380 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected]
381 colors = [(1.0, 1.0, 1.0), color] 381 colors = [(1.0, 1.0, 1.0), color]
382 draw_funcs = [self.__class__.fill_polyline, self.__class__.draw_polyline] 382 draw_funcs = [self.__class__.fill_polyline, self.__class__.draw_polyline]
383 for i in range(0, 2): 383 for i in range(0, 2):
384 color = colors[i] 384 color = colors[i]
385 draw_func = draw_funcs[i] 385 draw_func = draw_funcs[i]
386 386
387 draw_func(self, [(x, y), (x - big_arrowhead_height / Canvas.SQRT3, y + big_arrowhead_height), \ 387 draw_func(self, [(x, y), (x - big_arrowhead_height / Canvas.SQRT3, y + big_arrowhead_height), \
388 (x + big_arrowhead_height / Canvas.SQRT3, y + big_arrowhead_height), (x, y)], \ 388 (x + big_arrowhead_height / Canvas.SQRT3, y + big_arrowhead_height), (x, y)], \
389 color, GraphFormat.BORDER_THICKNESS) 389 color, GraphFormat.BORDER_THICKNESS)
390 390
391 self.draw_line((x, y + big_arrowhead_height), (x, y + height), color, GraphFormat.BORDER_THICKNESS) 391 self.draw_line((x, y + big_arrowhead_height), (x, y + height), color, GraphFormat.BORDER_THICKNESS)
392 392
393 def add_sel_release_arrow_big(self, x, y, height, event): 393 def add_sel_release_arrow_big(self, x, y, height, event):
394 self.add_sel_arrow_big(x, y, height, event) 394 self.add_sel_arrow_big(x, y, height, event)
395 395
396 def draw_deadline_arrow_big(self, x, y, height, selected): 396 def draw_deadline_arrow_big(self, x, y, height, selected):
397 """Draws a release arrow: x, y should give the top (northernmost 397 """Draws a release arrow: x, y should give the top (northernmost
398 point) of the arrow. The height includes the arrowhead.""" 398 point) of the arrow. The height includes the arrowhead."""
399 big_arrowhead_height = GraphFormat.BIG_ARROWHEAD_FACTOR * height 399 big_arrowhead_height = GraphFormat.BIG_ARROWHEAD_FACTOR * height
400 400
401 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected] 401 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected]
402 colors = [(1.0, 1.0, 1.0), color] 402 colors = [(1.0, 1.0, 1.0), color]
403 draw_funcs = [self.__class__.fill_polyline, self.__class__.draw_polyline] 403 draw_funcs = [self.__class__.fill_polyline, self.__class__.draw_polyline]
404 for i in range(0, 2): 404 for i in range(0, 2):
405 color = colors[i] 405 color = colors[i]
406 draw_func = draw_funcs[i] 406 draw_func = draw_funcs[i]
407 407
408 draw_func(self, [(x, y + height), (x - big_arrowhead_height / Canvas.SQRT3, \ 408 draw_func(self, [(x, y + height), (x - big_arrowhead_height / Canvas.SQRT3, \
409 y + height - big_arrowhead_height), \ 409 y + height - big_arrowhead_height), \
410 (x + big_arrowhead_height / Canvas.SQRT3, \ 410 (x + big_arrowhead_height / Canvas.SQRT3, \
411 y + height - big_arrowhead_height), \ 411 y + height - big_arrowhead_height), \
412 (x, y + height)], color, GraphFormat.BORDER_THICKNESS) 412 (x, y + height)], color, GraphFormat.BORDER_THICKNESS)
413 413
414 self.draw_line((x, y), (x, y + height - big_arrowhead_height), 414 self.draw_line((x, y), (x, y + height - big_arrowhead_height),
415 color, GraphFormat.BORDER_THICKNESS) 415 color, GraphFormat.BORDER_THICKNESS)
416 416
417 def add_sel_deadline_arrow_big(self, x, y, height, event): 417 def add_sel_deadline_arrow_big(self, x, y, height, event):
418 self.add_sel_arrow_big(x, y, height, event) 418 self.add_sel_arrow_big(x, y, height, event)
419 419
420 def add_sel_arrow_big(self, x, y, height, event): 420 def add_sel_arrow_big(self, x, y, height, event):
421 big_arrowhead_height = GraphFormat.BIG_ARROWHEAD_FACTOR * height 421 big_arrowhead_height = GraphFormat.BIG_ARROWHEAD_FACTOR * height
422 422
423 self.add_sel_region(SelectableRegion(x - big_arrowhead_height / Canvas.SQRT3, 423 self.add_sel_region(SelectableRegion(x - big_arrowhead_height / Canvas.SQRT3,
424 y, 2.0 * big_arrowhead_height / Canvas.SQRT3, height, event)) 424 y, 2.0 * big_arrowhead_height / Canvas.SQRT3, height, event))
425 425
426 def draw_release_arrow_small(self, x, y, height, selected): 426 def draw_release_arrow_small(self, x, y, height, selected):
427 """Draws a small release arrow (most likely coming off the x-axis, although 427 """Draws a small release arrow (most likely coming off the x-axis, although
428 this method doesn't enforce this): x, y should give the top of the arrow""" 428 this method doesn't enforce this): x, y should give the top of the arrow"""
429 small_arrowhead_height = GraphFormat.SMALL_ARROWHEAD_FACTOR * height 429 small_arrowhead_height = GraphFormat.SMALL_ARROWHEAD_FACTOR * height
430 430
431 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected] 431 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected]
432 432
433 self.draw_line((x, y), (x - small_arrowhead_height, y + small_arrowhead_height), \ 433 self.draw_line((x, y), (x - small_arrowhead_height, y + small_arrowhead_height), \
434 color, GraphFormat.BORDER_THICKNESS) 434 color, GraphFormat.BORDER_THICKNESS)
435 self.draw_line((x, y), (x + small_arrowhead_height, y + small_arrowhead_height), \ 435 self.draw_line((x, y), (x + small_arrowhead_height, y + small_arrowhead_height), \
436 color, GraphFormat.BORDER_THICKNESS) 436 color, GraphFormat.BORDER_THICKNESS)
437 self.draw_line((x, y), (x, y + height), color, GraphFormat.BORDER_THICKNESS) 437 self.draw_line((x, y), (x, y + height), color, GraphFormat.BORDER_THICKNESS)
438 438
439 def add_sel_release_arrow_small(self, x, y, height, event): 439 def add_sel_release_arrow_small(self, x, y, height, event):
440 self.add_sel_arrow_small(x, y, height, event) 440 self.add_sel_arrow_small(x, y, height, event)
441 441
442 def draw_deadline_arrow_small(self, x, y, height, selected): 442 def draw_deadline_arrow_small(self, x, y, height, selected):
443 """Draws a small deadline arrow (most likely coming off the x-axis, although 443 """Draws a small deadline arrow (most likely coming off the x-axis, although
444 this method doesn't enforce this): x, y should give the top of the arrow""" 444 this method doesn't enforce this): x, y should give the top of the arrow"""
445 small_arrowhead_height = GraphFormat.SMALL_ARROWHEAD_FACTOR * height 445 small_arrowhead_height = GraphFormat.SMALL_ARROWHEAD_FACTOR * height
446 446
447 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected] 447 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected]
448 448
449 self.draw_line((x, y), (x, y + height), color, GraphFormat.BORDER_THICKNESS) 449 self.draw_line((x, y), (x, y + height), color, GraphFormat.BORDER_THICKNESS)
450 self.draw_line((x - small_arrowhead_height, y + height - small_arrowhead_height), \ 450 self.draw_line((x - small_arrowhead_height, y + height - small_arrowhead_height), \
451 (x, y + height), color, GraphFormat.BORDER_THICKNESS) 451 (x, y + height), color, GraphFormat.BORDER_THICKNESS)
452 self.draw_line((x + small_arrowhead_height, y + height - small_arrowhead_height), \ 452 self.draw_line((x + small_arrowhead_height, y + height - small_arrowhead_height), \
453 (x, y + height), color, GraphFormat.BORDER_THICKNESS) 453 (x, y + height), color, GraphFormat.BORDER_THICKNESS)
454 454
455 def add_sel_deadline_arrow_small(self, x, y, height, event): 455 def add_sel_deadline_arrow_small(self, x, y, height, event):
456 self.add_sel_arrow_small(x, y, height, event) 456 self.add_sel_arrow_small(x, y, height, event)
457 457
458 def add_sel_arrow_small(self, x, y, height, event): 458 def add_sel_arrow_small(self, x, y, height, event):
459 small_arrowhead_height = GraphFormat.SMALL_ARROWHEAD_FACTOR * height 459 small_arrowhead_height = GraphFormat.SMALL_ARROWHEAD_FACTOR * height
460 460
461 self.add_sel_region(SelectableRegion(x - small_arrowhead_height, y, 461 self.add_sel_region(SelectableRegion(x - small_arrowhead_height, y,
462 small_arrowhead_height * 2.0, height, event)) 462 small_arrowhead_height * 2.0, height, event))
463 463
464 def draw_suspend_triangle(self, x, y, height, selected): 464 def draw_suspend_triangle(self, x, y, height, selected):
465 """Draws the triangle that marks a suspension. (x, y) gives the topmost (northernmost) point 465 """Draws the triangle that marks a suspension. (x, y) gives the topmost (northernmost) point
466 of the symbol.""" 466 of the symbol."""
467 467
468 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected] 468 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected]
469 colors = [(0.0, 0.0, 0.0), color] 469 colors = [(0.0, 0.0, 0.0), color]
470 470
471 draw_funcs = [self.__class__.fill_polyline, self.__class__.draw_polyline] 471 draw_funcs = [self.__class__.fill_polyline, self.__class__.draw_polyline]
472 for i in range(0, 2): 472 for i in range(0, 2):
473 color = colors[i] 473 color = colors[i]
474 draw_func = draw_funcs[i] 474 draw_func = draw_funcs[i]
475 draw_func(self, [(x, y), (x + height / 2.0, y + height / 2.0), (x, y + height), (x, y)], \ 475 draw_func(self, [(x, y), (x + height / 2.0, y + height / 2.0), (x, y + height), (x, y)], \
476 color, GraphFormat.BORDER_THICKNESS) 476 color, GraphFormat.BORDER_THICKNESS)
477 477
478 def add_sel_suspend_triangle(self, x, y, height, event): 478 def add_sel_suspend_triangle(self, x, y, height, event):
479 self.add_sel_region(SelectableRegion(x, y, height / 2.0, height, event)) 479 self.add_sel_region(SelectableRegion(x, y, height / 2.0, height, event))
480 480
481 def draw_resume_triangle(self, x, y, height, selected): 481 def draw_resume_triangle(self, x, y, height, selected):
482 """Draws the triangle that marks a resumption. (x, y) gives the topmost (northernmost) point 482 """Draws the triangle that marks a resumption. (x, y) gives the topmost (northernmost) point
483 of the symbol.""" 483 of the symbol."""
484 484
485 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected] 485 color = {False : GraphFormat.BORDER_COLOR, True : GraphFormat.HIGHLIGHT_COLOR}[selected]
486 colors = [(1.0, 1.0, 1.0), color] 486 colors = [(1.0, 1.0, 1.0), color]
487 487
488 draw_funcs = [self.__class__.fill_polyline, self.__class__.draw_polyline] 488 draw_funcs = [self.__class__.fill_polyline, self.__class__.draw_polyline]
489 for i in range(0, 2): 489 for i in range(0, 2):
490 color = colors[i] 490 color = colors[i]
491 draw_func = draw_funcs[i] 491 draw_func = draw_funcs[i]
492 draw_func(self, [(x, y), (x - height / 2.0, y + height / 2.0), (x, y + height), (x, y)], \ 492 draw_func(self, [(x, y), (x - height / 2.0, y + height / 2.0), (x, y + height), (x, y)], \
493 color, GraphFormat.BORDER_THICKNESS) 493 color, GraphFormat.BORDER_THICKNESS)
494 494
495 def add_sel_resume_triangle(self, x, y, height, event): 495 def add_sel_resume_triangle(self, x, y, height, event):
496 self.add_sel_region(SelectableRegion(x - height / 2.0, y, height / 2.0, height, event)) 496 self.add_sel_region(SelectableRegion(x - height / 2.0, y, height / 2.0, height, event))
497 497
498 def clear_selectable_regions(self, real_x, real_y, width, height): 498 def clear_selectable_regions(self, real_x, real_y, width, height):
499 x = real_x + self.surface.virt_x 499 x = real_x + self.surface.virt_x
500 y = real_y + self.surface.virt_y 500 y = real_y + self.surface.virt_y
501 for event in self.selectable_regions.keys(): 501 for event in self.selectable_regions.keys():
502 if self.selectable_regions[event].intersects(x, y, width, height): 502 if self.selectable_regions[event].intersects(x, y, width, height):
503 del self.selectable_regions[event] 503 del self.selectable_regions[event]
504 504
505 def add_sel_region(self, region): 505 def add_sel_region(self, region):
506 self.selectable_regions[region.get_event()] = region 506 self.selectable_regions[region.get_event()] = region
507 507
508 def get_sel_region(self, event): 508 def get_sel_region(self, event):
509 return self.selectable_regions[event] 509 return self.selectable_regions[event]
510 510
511 def get_selected_regions(self, real_x, real_y, width, height): 511 def get_selected_regions(self, real_x, real_y, width, height):
512 x = real_x + self.surface.virt_x 512 x = real_x + self.surface.virt_x
513 y = real_y + self.surface.virt_y 513 y = real_y + self.surface.virt_y
514 514
515 selected = {} 515 selected = {}
516 for event in self.selectable_regions: 516 for event in self.selectable_regions:
517 region = self.selectable_regions[event] 517 region = self.selectable_regions[event]
518 if region.intersects(x, y, width, height): 518 if region.intersects(x, y, width, height):
519 selected[event] = region 519 selected[event] = region
520 520
521 return selected 521 return selected
522 522
523 def whiteout(self, real_x, real_y, width, height): 523 def whiteout(self, real_x, real_y, width, height):
524 """Overwrites the surface completely white, but technically doesn't delete anything""" 524 """Overwrites the surface completely white, but technically doesn't delete anything"""
525 self.fill_rect(self.surface.virt_x + real_x, self.surface.virt_y + real_y, width, 525 self.fill_rect(self.surface.virt_x + real_x, self.surface.virt_y + real_y, width,
526 height, (1.0, 1.0, 1.0), False) 526 height, (1.0, 1.0, 1.0), False)
527 527
528 def get_item_color(self, n): 528 def get_item_color(self, n):
529 """Gets the nth color in the item color list, which are the colors used to draw the items 529 """Gets the nth color in the item color list, which are the colors used to draw the items
530 on the y-axis. Note that there are conceptually infinitely 530 on the y-axis. Note that there are conceptually infinitely
531 many patterns because the patterns repeat -- that is, we just mod out by the size of the pattern 531 many patterns because the patterns repeat -- that is, we just mod out by the size of the pattern
532 list when indexing.""" 532 list when indexing."""
533 return self.item_clist[n % len(self.item_clist)] 533 return self.item_clist[n % len(self.item_clist)]
534 534
535 def get_bar_pattern(self, n): 535 def get_bar_pattern(self, n):
536 """Gets the nth pattern in the bar pattern list, which is a list of surfaces that are used to 536 """Gets the nth pattern in the bar pattern list, which is a list of surfaces that are used to
537 fill in the bars. Note that there are conceptually infinitely 537 fill in the bars. Note that there are conceptually infinitely
@@ -545,30 +545,30 @@ class CairoCanvas(Canvas):
545 """This is a basic class that stores and draws on a Cairo surface, 545 """This is a basic class that stores and draws on a Cairo surface,
546 using various primitives related to drawing a real-time graph (up-arrows, 546 using various primitives related to drawing a real-time graph (up-arrows,
547 down-arrows, bars, ...). 547 down-arrows, bars, ...).
548 548
549 This is the lowest-level non-abstract representation 549 This is the lowest-level non-abstract representation
550 (aside perhaps from the Cairo surface itself) of a real-time graph. 550 (aside perhaps from the Cairo surface itself) of a real-time graph.
551 It allows the user to draw primitives at certain locations, but for 551 It allows the user to draw primitives at certain locations, but for
552 the most part does not know anything about real-time scheduling, 552 the most part does not know anything about real-time scheduling,
553 just how to draw the basic parts that make up a schedule graph. 553 just how to draw the basic parts that make up a schedule graph.
554 For that, see Graph or its descendants.""" 554 For that, see Graph or its descendants."""
555 555
556 #def __init__(self, fname, width, height, item_clist, bar_plist, surface): 556 #def __init__(self, fname, width, height, item_clist, bar_plist, surface):
557 # """Creates a new Canvas of dimensions (width, height). The 557 # """Creates a new Canvas of dimensions (width, height). The
558 # parameters ``item_plist'' and ``bar_plist'' each specify a list 558 # parameters ``item_plist'' and ``bar_plist'' each specify a list
559 # of patterns to choose from when drawing the items on the y-axis 559 # of patterns to choose from when drawing the items on the y-axis
560 # or filling in bars, respectively.""" 560 # or filling in bars, respectively."""
561 561
562 # super(CairoCanvas, self).__init__(fname, width, height, item_clist, bar_plist, surface) 562 # super(CairoCanvas, self).__init__(fname, width, height, item_clist, bar_plist, surface)
563 563
564 #def clear(self): 564 #def clear(self):
565 # self.surface = self.SurfaceType(self.width, self.height, self.fname) 565 # self.surface = self.SurfaceType(self.width, self.height, self.fname)
566 # self.whiteout() 566 # self.whiteout()
567 567
568 def get_surface(self): 568 def get_surface(self):
569 """Gets the Surface that we are drawing on in its current state.""" 569 """Gets the Surface that we are drawing on in its current state."""
570 return self.surface 570 return self.surface
571 571
572 def _rect_common(self, x, y, width, height, color, thickness, do_snap=True): 572 def _rect_common(self, x, y, width, height, color, thickness, do_snap=True):
573 x, y, width, height = self.scaled(x, y, width, height) 573 x, y, width, height = self.scaled(x, y, width, height)
574 x, y = self.surface.get_real_coor(x, y) 574 x, y = self.surface.get_real_coor(x, y)
@@ -576,23 +576,23 @@ class CairoCanvas(Canvas):
576 self.surface.ctx.rectangle(snap(x), snap(y), width, height) 576 self.surface.ctx.rectangle(snap(x), snap(y), width, height)
577 else: 577 else:
578 self.surface.ctx.rectangle(x, y, width, height) 578 self.surface.ctx.rectangle(x, y, width, height)
579 579
580 self.surface.ctx.set_line_width(thickness * self.scale) 580 self.surface.ctx.set_line_width(thickness * self.scale)
581 self.surface.ctx.set_source_rgb(color[0], color[1], color[2]) 581 self.surface.ctx.set_source_rgb(color[0], color[1], color[2])
582 582
583 def draw_rect(self, x, y, width, height, color, thickness, do_snap=True): 583 def draw_rect(self, x, y, width, height, color, thickness, do_snap=True):
584 self._rect_common(x, y, width, height, color, thickness, do_snap) 584 self._rect_common(x, y, width, height, color, thickness, do_snap)
585 self.surface.ctx.stroke() 585 self.surface.ctx.stroke()
586 586
587 def fill_rect(self, x, y, width, height, color, do_snap=True): 587 def fill_rect(self, x, y, width, height, color, do_snap=True):
588 self._rect_common(x, y, width, height, color, 1, do_snap) 588 self._rect_common(x, y, width, height, color, 1, do_snap)
589 self.surface.ctx.fill() 589 self.surface.ctx.fill()
590 590
591 def fill_rect_fade(self, x, y, width, height, lcolor, rcolor, do_snap=True): 591 def fill_rect_fade(self, x, y, width, height, lcolor, rcolor, do_snap=True):
592 """Draws a rectangle somewhere, filled in with the fade.""" 592 """Draws a rectangle somewhere, filled in with the fade."""
593 x, y, width, height = self.scaled(x, y, width, height) 593 x, y, width, height = self.scaled(x, y, width, height)
594 x, y = self.surface.get_real_coor(x, y) 594 x, y = self.surface.get_real_coor(x, y)
595 595
596 if do_snap: 596 if do_snap:
597 linear = cairo.LinearGradient(snap(x), snap(y), \ 597 linear = cairo.LinearGradient(snap(x), snap(y), \
598 snap(x + width), snap(y + height)) 598 snap(x + width), snap(y + height))
@@ -607,7 +607,7 @@ class CairoCanvas(Canvas):
607 else: 607 else:
608 self.surface.ctx.rectangle(snap(x), snap(y), width, height) 608 self.surface.ctx.rectangle(snap(x), snap(y), width, height)
609 self.surface.ctx.fill() 609 self.surface.ctx.fill()
610 610
611 def draw_line(self, p0, p1, color, thickness, do_snap=True): 611 def draw_line(self, p0, p1, color, thickness, do_snap=True):
612 """Draws a line from p0 to p1 with a certain color and thickness.""" 612 """Draws a line from p0 to p1 with a certain color and thickness."""
613 p0 = self.scaled(p0[0], p0[1]) 613 p0 = self.scaled(p0[0], p0[1])
@@ -617,34 +617,34 @@ class CairoCanvas(Canvas):
617 if do_snap: 617 if do_snap:
618 p0 = (snap(p0[0]), snap(p0[1])) 618 p0 = (snap(p0[0]), snap(p0[1]))
619 p1 = (snap(p1[0]), snap(p1[1])) 619 p1 = (snap(p1[0]), snap(p1[1]))
620 620
621 self.surface.ctx.move_to(p0[0], p0[1]) 621 self.surface.ctx.move_to(p0[0], p0[1])
622 self.surface.ctx.line_to(p1[0], p1[1]) 622 self.surface.ctx.line_to(p1[0], p1[1])
623 self.surface.ctx.set_source_rgb(color[0], color[1], color[2]) 623 self.surface.ctx.set_source_rgb(color[0], color[1], color[2])
624 self.surface.ctx.set_line_width(thickness * self.scale) 624 self.surface.ctx.set_line_width(thickness * self.scale)
625 self.surface.ctx.stroke() 625 self.surface.ctx.stroke()
626 626
627 def _polyline_common(self, coor_list, color, thickness, do_snap=True): 627 def _polyline_common(self, coor_list, color, thickness, do_snap=True):
628 real_coor_list = [self.surface.get_real_coor(coor[0], coor[1]) for coor in coor_list] 628 real_coor_list = [self.surface.get_real_coor(coor[0], coor[1]) for coor in coor_list]
629 self.surface.ctx.move_to(real_coor_list[0][0], real_coor_list[0][1]) 629 self.surface.ctx.move_to(real_coor_list[0][0], real_coor_list[0][1])
630 if do_snap: 630 if do_snap:
631 for i in range(0, len(real_coor_list)): 631 for i in range(0, len(real_coor_list)):
632 real_coor_list[i] = (snap(real_coor_list[i][0]), snap(real_coor_list[i][1])) 632 real_coor_list[i] = (snap(real_coor_list[i][0]), snap(real_coor_list[i][1]))
633 633
634 for coor in real_coor_list[1:]: 634 for coor in real_coor_list[1:]:
635 self.surface.ctx.line_to(coor[0], coor[1]) 635 self.surface.ctx.line_to(coor[0], coor[1])
636 636
637 self.surface.ctx.set_line_width(thickness) 637 self.surface.ctx.set_line_width(thickness)
638 self.surface.ctx.set_source_rgb(color[0], color[1], color[2]) 638 self.surface.ctx.set_source_rgb(color[0], color[1], color[2])
639 639
640 def draw_polyline(self, coor_list, color, thickness, do_snap=True): 640 def draw_polyline(self, coor_list, color, thickness, do_snap=True):
641 self._polyline_common(coor_list, color, thickness, do_snap) 641 self._polyline_common(coor_list, color, thickness, do_snap)
642 self.surface.ctx.stroke() 642 self.surface.ctx.stroke()
643 643
644 def fill_polyline(self, coor_list, color, thickness, do_snap=True): 644 def fill_polyline(self, coor_list, color, thickness, do_snap=True):
645 self._polyline_common(coor_list, color, thickness, do_snap) 645 self._polyline_common(coor_list, color, thickness, do_snap)
646 self.surface.ctx.fill() 646 self.surface.ctx.fill()
647 647
648 def _draw_label_common(self, text, x, y, fopts, x_bearing_factor, \ 648 def _draw_label_common(self, text, x, y, fopts, x_bearing_factor, \
649 f_descent_factor, width_factor, f_height_factor, do_snap=True): 649 f_descent_factor, width_factor, f_height_factor, do_snap=True):
650 """Helper function for drawing a label with some alignment. Instead of taking in an alignment, 650 """Helper function for drawing a label with some alignment. Instead of taking in an alignment,
@@ -652,30 +652,30 @@ class CairoCanvas(Canvas):
652 the x and y parameters. Only should be used internally.""" 652 the x and y parameters. Only should be used internally."""
653 x, y = self.scaled(x, y) 653 x, y = self.scaled(x, y)
654 x, y = self.surface.get_real_coor(x, y) 654 x, y = self.surface.get_real_coor(x, y)
655 655
656 self.surface.ctx.set_source_rgb(0.0, 0.0, 0.0) 656 self.surface.ctx.set_source_rgb(0.0, 0.0, 0.0)
657 657
658 self.surface.ctx.select_font_face(fopts.name, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) 658 self.surface.ctx.select_font_face(fopts.name, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
659 self.surface.ctx.set_font_size(fopts.size) 659 self.surface.ctx.set_font_size(fopts.size)
660 660
661 fe = self.surface.ctx.font_extents() 661 fe = self.surface.ctx.font_extents()
662 f_ascent, f_descent, f_height = fe[:3] 662 f_ascent, f_descent, f_height = fe[:3]
663 663
664 te = self.surface.ctx.text_extents(text) 664 te = self.surface.ctx.text_extents(text)
665 x_bearing, y_bearing, width, height = te[:4] 665 x_bearing, y_bearing, width, height = te[:4]
666 666
667 actual_x = x - x_bearing * x_bearing_factor - width * width_factor 667 actual_x = x - x_bearing * x_bearing_factor - width * width_factor
668 actual_y = y - f_descent * f_descent_factor + f_height * f_height_factor 668 actual_y = y - f_descent * f_descent_factor + f_height * f_height_factor
669 669
670 self.surface.ctx.set_source_rgb(fopts.color[0], fopts.color[1], fopts.color[2]) 670 self.surface.ctx.set_source_rgb(fopts.color[0], fopts.color[1], fopts.color[2])
671 671
672 if do_snap: 672 if do_snap:
673 self.surface.ctx.move_to(snap(actual_x), snap(actual_y)) 673 self.surface.ctx.move_to(snap(actual_x), snap(actual_y))
674 else: 674 else:
675 self.surface.ctx.move_to(actual_x, actual_y) 675 self.surface.ctx.move_to(actual_x, actual_y)
676 676
677 self.surface.ctx.show_text(text) 677 self.surface.ctx.show_text(text)
678 678
679 def draw_label(self, text, x, y, fopts=GraphFormat.DEF_FOPTS_LABEL, halign=AlignMode.LEFT, valign=AlignMode.BOTTOM, do_snap=True): 679 def draw_label(self, text, x, y, fopts=GraphFormat.DEF_FOPTS_LABEL, halign=AlignMode.LEFT, valign=AlignMode.BOTTOM, do_snap=True):
680 """Draws a label with the given parameters, with the given horizontal and vertical justification. One can override 680 """Draws a label with the given parameters, with the given horizontal and vertical justification. One can override
681 the color from ``fopts'' by passing something in to ``pattern'', which overrides the color with an arbitrary 681 the color from ``fopts'' by passing something in to ``pattern'', which overrides the color with an arbitrary
@@ -685,21 +685,21 @@ class CairoCanvas(Canvas):
685 if halign not in halign_factors: 685 if halign not in halign_factors:
686 raise ValueError('Invalid alignment value') 686 raise ValueError('Invalid alignment value')
687 x_bearing_factor, width_factor = halign_factors[halign] 687 x_bearing_factor, width_factor = halign_factors[halign]
688 688
689 valign_factors = {AlignMode.BOTTOM : (0.0, 0.0), AlignMode.CENTER : (1.0, 0.5), AlignMode.TOP : (1.0, 1.0)} 689 valign_factors = {AlignMode.BOTTOM : (0.0, 0.0), AlignMode.CENTER : (1.0, 0.5), AlignMode.TOP : (1.0, 1.0)}
690 if valign not in valign_factors: 690 if valign not in valign_factors:
691 raise ValueError('Invalid alignment value') 691 raise ValueError('Invalid alignment value')
692 f_descent_factor, f_height_factor = valign_factors[valign] 692 f_descent_factor, f_height_factor = valign_factors[valign]
693 693
694 self._draw_label_common(text, x, y, fopts, x_bearing_factor, \ 694 self._draw_label_common(text, x, y, fopts, x_bearing_factor, \
695 f_descent_factor, width_factor, f_height_factor, do_snap) 695 f_descent_factor, width_factor, f_height_factor, do_snap)
696 696
697 def draw_label_with_sscripts(self, text, supscript, subscript, x, y, \ 697 def draw_label_with_sscripts(self, text, supscript, subscript, x, y, \
698 textfopts=GraphFormat.DEF_FOPTS_LABEL, sscriptfopts=GraphFormat.DEF_FOPTS_LABEL_SSCRIPT, \ 698 textfopts=GraphFormat.DEF_FOPTS_LABEL, sscriptfopts=GraphFormat.DEF_FOPTS_LABEL_SSCRIPT, \
699 halign=AlignMode.LEFT, valign=AlignMode.BOTTOM, do_snap=True): 699 halign=AlignMode.LEFT, valign=AlignMode.BOTTOM, do_snap=True):
700 """Draws a label, but also optionally allows a superscript and subscript to be rendered.""" 700 """Draws a label, but also optionally allows a superscript and subscript to be rendered."""
701 self.draw_label(text, x, y, textfopts, halign, valign) 701 self.draw_label(text, x, y, textfopts, halign, valign)
702 702
703 self.surface.ctx.set_source_rgb(0.0, 0.0, 0.0) 703 self.surface.ctx.set_source_rgb(0.0, 0.0, 0.0)
704 self.surface.ctx.select_font_face(textfopts.name, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) 704 self.surface.ctx.select_font_face(textfopts.name, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
705 self.surface.ctx.set_font_size(textfopts.size) 705 self.surface.ctx.set_font_size(textfopts.size)
@@ -719,7 +719,7 @@ class CairoCanvas(Canvas):
719 ytmp = y 719 ytmp = y
720 ytmp = y + f_height / 4.0 720 ytmp = y + f_height / 4.0
721 self.draw_label(subscript, xtmp, ytmp, sscriptfopts, halign, valign, do_snap) 721 self.draw_label(subscript, xtmp, ytmp, sscriptfopts, halign, valign, do_snap)
722 722
723# represents a selectable region of the graph 723# represents a selectable region of the graph
724class SelectableRegion(object): 724class SelectableRegion(object):
725 def __init__(self, x, y, width, height, event): 725 def __init__(self, x, y, width, height, event):
@@ -728,23 +728,23 @@ class SelectableRegion(object):
728 self.width = width 728 self.width = width
729 self.height = height 729 self.height = height
730 self.event = event 730 self.event = event
731 731
732 def get_dimensions(self): 732 def get_dimensions(self):
733 return (self.x, self.y, self.width, self.height) 733 return (self.x, self.y, self.width, self.height)
734 734
735 def get_event(self): 735 def get_event(self):
736 return self.event 736 return self.event
737 737
738 def intersects(self, x, y, width, height): 738 def intersects(self, x, y, width, height):
739 return x <= self.x + self.width and x + width >= self.x and y <= self.y + self.height and y + height >= self.y 739 return x <= self.x + self.width and x + width >= self.x and y <= self.y + self.height and y + height >= self.y
740 740
741class Graph(object): 741class Graph(object):
742 DEF_BAR_PLIST = [Pattern([(0.0, 0.9, 0.9)]), Pattern([(0.9, 0.3, 0.0)]), Pattern([(0.9, 0.7, 0.0)]), 742 DEF_BAR_PLIST = [Pattern([(0.0, 0.9, 0.9)]), Pattern([(0.9, 0.3, 0.0)]), Pattern([(0.9, 0.7, 0.0)]),
743 Pattern([(0.0, 0.0, 0.8)]), Pattern([(0.0, 0.2, 0.9)]), Pattern([(0.0, 0.6, 0.6)]), 743 Pattern([(0.0, 0.0, 0.8)]), Pattern([(0.0, 0.2, 0.9)]), Pattern([(0.0, 0.6, 0.6)]),
744 Pattern([(0.75, 0.75, 0.75)])] 744 Pattern([(0.75, 0.75, 0.75)])]
745 DEF_ITEM_CLIST = [(0.3, 0.0, 0.0), (0.0, 0.3, 0.0), (0.0, 0.0, 0.3), (0.3, 0.3, 0.0), (0.0, 0.3, 0.3), 745 DEF_ITEM_CLIST = [(0.3, 0.0, 0.0), (0.0, 0.3, 0.0), (0.0, 0.0, 0.3), (0.3, 0.3, 0.0), (0.0, 0.3, 0.3),
746 (0.3, 0.0, 0.3)] 746 (0.3, 0.0, 0.3)]
747 747
748 def __init__(self, CanvasType, surface, start_time, end_time, y_item_list, attrs=GraphFormat(), 748 def __init__(self, CanvasType, surface, start_time, end_time, y_item_list, attrs=GraphFormat(),
749 item_clist=DEF_ITEM_CLIST, bar_plist=DEF_BAR_PLIST): 749 item_clist=DEF_ITEM_CLIST, bar_plist=DEF_BAR_PLIST):
750 # deal with possibly blank schedules 750 # deal with possibly blank schedules
@@ -752,16 +752,16 @@ class Graph(object):
752 start_time = 0 752 start_time = 0
753 if end_time is None: 753 if end_time is None:
754 end_time = 0 754 end_time = 0
755 755
756 if start_time > end_time: 756 if start_time > end_time:
757 raise ValueError("Litmus is not a time machine") 757 raise ValueError("Litmus is not a time machine")
758 758
759 self.attrs = attrs 759 self.attrs = attrs
760 self.start_time = start_time 760 self.start_time = start_time
761 self.end_time = end_time 761 self.end_time = end_time
762 self.y_item_list = y_item_list 762 self.y_item_list = y_item_list
763 self.num_maj = int(math.ceil((self.end_time - self.start_time) * 1.0 / self.attrs.time_per_maj)) + 1 763 self.num_maj = int(math.ceil((self.end_time - self.start_time) * 1.0 / self.attrs.time_per_maj)) + 1
764 764
765 width = self.num_maj * self.attrs.maj_sep + GraphFormat.X_AXIS_MEASURE_OFS + GraphFormat.WIDTH_PAD 765 width = self.num_maj * self.attrs.maj_sep + GraphFormat.X_AXIS_MEASURE_OFS + GraphFormat.WIDTH_PAD
766 height = (len(self.y_item_list) + 1) * self.attrs.y_item_size + GraphFormat.HEIGHT_PAD 766 height = (len(self.y_item_list) + 1) * self.attrs.y_item_size + GraphFormat.HEIGHT_PAD
767 767
@@ -771,7 +771,7 @@ class Graph(object):
771 extra_width = 0.0 771 extra_width = 0.0
772 dummy_surface = surface.__class__() 772 dummy_surface = surface.__class__()
773 dummy_surface.renew(10, 10) 773 dummy_surface.renew(10, 10)
774 774
775 dummy_surface.ctx.select_font_face(self.attrs.item_fopts.name, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) 775 dummy_surface.ctx.select_font_face(self.attrs.item_fopts.name, cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
776 dummy_surface.ctx.set_font_size(self.attrs.item_fopts.size) 776 dummy_surface.ctx.set_font_size(self.attrs.item_fopts.size)
777 for item in self.y_item_list: 777 for item in self.y_item_list:
@@ -780,45 +780,45 @@ class Graph(object):
780 cur_width = te[2] 780 cur_width = te[2]
781 if cur_width > extra_width: 781 if cur_width > extra_width:
782 extra_width = cur_width 782 extra_width = cur_width
783 783
784 width += extra_width 784 width += extra_width
785 785
786 self.origin = (extra_width + GraphFormat.WIDTH_PAD / 2.0, height - GraphFormat.HEIGHT_PAD / 2.0) 786 self.origin = (extra_width + GraphFormat.WIDTH_PAD / 2.0, height - GraphFormat.HEIGHT_PAD / 2.0)
787 787
788 self.width = width 788 self.width = width
789 self.height = height 789 self.height = height
790 790
791 #if surface.ctx is None: 791 #if surface.ctx is None:
792 # surface.renew(width, height) 792 # surface.renew(width, height)
793 793
794 self.canvas = CanvasType(width, height, item_clist, bar_plist, surface) 794 self.canvas = CanvasType(width, height, item_clist, bar_plist, surface)
795 795
796 def get_selected_regions(self, real_x, real_y, width, height): 796 def get_selected_regions(self, real_x, real_y, width, height):
797 return self.canvas.get_selected_regions(real_x, real_y, width, height) 797 return self.canvas.get_selected_regions(real_x, real_y, width, height)
798 798
799 def get_width(self): 799 def get_width(self):
800 return self.width 800 return self.width
801 801
802 def get_height(self): 802 def get_height(self):
803 return self.height 803 return self.height
804 804
805 def get_origin(self): 805 def get_origin(self):
806 return self.origin 806 return self.origin
807 807
808 def get_attrs(self): 808 def get_attrs(self):
809 return self.attrs 809 return self.attrs
810 810
811 def add_sel_region(self, region): 811 def add_sel_region(self, region):
812 self.canvas.add_sel_region(region) 812 self.canvas.add_sel_region(region)
813 813
814 def get_sel_region(self, event): 814 def get_sel_region(self, event):
815 return self.canvas.get_sel_region(event) 815 return self.canvas.get_sel_region(event)
816 816
817 def update_view(self, x, y, width, height, ctx): 817 def update_view(self, x, y, width, height, ctx):
818 """Proxy into the surface's pan.""" 818 """Proxy into the surface's pan."""
819 self.canvas.surface.pan(x, y, width, height) 819 self.canvas.surface.pan(x, y, width, height)
820 self.canvas.surface.change_ctx(ctx) 820 self.canvas.surface.change_ctx(ctx)
821 821
822 def _recomp_min_max(self, start_time, end_time, start_item, end_item): 822 def _recomp_min_max(self, start_time, end_time, start_item, end_item):
823 if self.min_time is None or start_time < self.min_time: 823 if self.min_time is None or start_time < self.min_time:
824 self.min_time = start_time 824 self.min_time = start_time
@@ -828,79 +828,79 @@ class Graph(object):
828 self.min_item = start_item 828 self.min_item = start_item
829 if self.max_item is None or end_item > self.max_item: 829 if self.max_item is None or end_item > self.max_item:
830 self.max_item = end_item 830 self.max_item = end_item
831 831
832 def _get_time_xpos(self, time): 832 def _get_time_xpos(self, time):
833 """get x so that x is at instant ``time'' on the graph""" 833 """get x so that x is at instant ``time'' on the graph"""
834 return self.origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + 1.0 * (time - self.start_time) / self.attrs.time_per_maj * self.attrs.maj_sep 834 return self.origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + 1.0 * (time - self.start_time) / self.attrs.time_per_maj * self.attrs.maj_sep
835 835
836 def _get_item_ypos(self, item_no): 836 def _get_item_ypos(self, item_no):
837 """get y so that y is where the top of a bar would be in item #n's area""" 837 """get y so that y is where the top of a bar would be in item #n's area"""
838 return self.origin[1] - self._get_y_axis_height() + self.attrs.y_item_size * (item_no + 0.5 - GraphFormat.BAR_SIZE_FACTOR / 2.0) 838 return self.origin[1] - self._get_y_axis_height() + self.attrs.y_item_size * (item_no + 0.5 - GraphFormat.BAR_SIZE_FACTOR / 2.0)
839 839
840 def _get_bar_width(self, start_time, end_time): 840 def _get_bar_width(self, start_time, end_time):
841 return 1.0 * (end_time - start_time) / self.attrs.time_per_maj * self.attrs.maj_sep 841 return 1.0 * (end_time - start_time) / self.attrs.time_per_maj * self.attrs.maj_sep
842 842
843 def _get_bar_height(self): 843 def _get_bar_height(self):
844 return self.attrs.y_item_size * GraphFormat.BAR_SIZE_FACTOR 844 return self.attrs.y_item_size * GraphFormat.BAR_SIZE_FACTOR
845 845
846 def _get_mini_bar_height(self): 846 def _get_mini_bar_height(self):
847 return self.attrs.y_item_size * GraphFormat.MINI_BAR_SIZE_FACTOR 847 return self.attrs.y_item_size * GraphFormat.MINI_BAR_SIZE_FACTOR
848 848
849 def _get_mini_bar_ofs(self): 849 def _get_mini_bar_ofs(self):
850 return self.attrs.y_item_size * (GraphFormat.MINI_BAR_SIZE_FACTOR + GraphFormat.BAR_MINI_BAR_GAP_FACTOR) 850 return self.attrs.y_item_size * (GraphFormat.MINI_BAR_SIZE_FACTOR + GraphFormat.BAR_MINI_BAR_GAP_FACTOR)
851 851
852 def _get_y_axis_height(self): 852 def _get_y_axis_height(self):
853 return (len(self.y_item_list) + 1) * self.attrs.y_item_size 853 return (len(self.y_item_list) + 1) * self.attrs.y_item_size
854 854
855 def _get_bottom_tick(self, time): 855 def _get_bottom_tick(self, time):
856 return int(math.floor((time - self.start_time) / self.attrs.time_per_maj)) 856 return int(math.floor((time - self.start_time) / self.attrs.time_per_maj))
857 857
858 def _get_top_tick(self, time): 858 def _get_top_tick(self, time):
859 return int(math.ceil((time - self.start_time) / self.attrs.time_per_maj)) 859 return int(math.ceil((time - self.start_time) / self.attrs.time_per_maj))
860 860
861 def get_surface(self): 861 def get_surface(self):
862 """Gets the underlying surface.""" 862 """Gets the underlying surface."""
863 return self.canvas.get_surface() 863 return self.canvas.get_surface()
864 864
865 def xcoor_to_time(self, x): 865 def xcoor_to_time(self, x):
866 #x = self.origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + (time - self.start) / self.attrs.time_per_maj * self.attrs.maj_sep 866 #x = self.origin[0] + GraphFormat.X_AXIS_MEASURE_OFS + (time - self.start) / self.attrs.time_per_maj * self.attrs.maj_sep
867 return (x - self.origin[0] - GraphFormat.X_AXIS_MEASURE_OFS) / self.attrs.maj_sep \ 867 return (x - self.origin[0] - GraphFormat.X_AXIS_MEASURE_OFS) / self.attrs.maj_sep \
868 * self.attrs.time_per_maj + self.start_time 868 * self.attrs.time_per_maj + self.start_time
869 869
870 def ycoor_to_item_no(self, y): 870 def ycoor_to_item_no(self, y):
871 return int((y - self.origin[1] + self._get_y_axis_height()) // self.attrs.y_item_size) 871 return int((y - self.origin[1] + self._get_y_axis_height()) // self.attrs.y_item_size)
872 872
873 def get_offset_params(self, real_x, real_y, width, height): 873 def get_offset_params(self, real_x, real_y, width, height):
874 start_time = self.xcoor_to_time(self.canvas.surface.virt_x + real_x) 874 start_time = self.xcoor_to_time(self.canvas.surface.virt_x + real_x)
875 end_time = self.xcoor_to_time(self.canvas.surface.virt_x + real_x + width) 875 end_time = self.xcoor_to_time(self.canvas.surface.virt_x + real_x + width)
876 876
877 start_item = self.ycoor_to_item_no(self.canvas.surface.virt_y + real_y) 877 start_item = self.ycoor_to_item_no(self.canvas.surface.virt_y + real_y)
878 end_item = 2 + self.ycoor_to_item_no(self.canvas.surface.virt_y + real_y + height) 878 end_item = 2 + self.ycoor_to_item_no(self.canvas.surface.virt_y + real_y + height)
879 879
880 return (start_time, end_time, start_item, end_item) 880 return (start_time, end_time, start_item, end_item)
881 881
882 def draw_skeleton(self, start_time, end_time, start_item, end_item): 882 def draw_skeleton(self, start_time, end_time, start_item, end_item):
883 self.draw_grid_at_time(start_time, end_time, start_item, end_item) 883 self.draw_grid_at_time(start_time, end_time, start_item, end_item)
884 self.draw_x_axis_with_labels_at_time(start_time, end_time) 884 self.draw_x_axis_with_labels_at_time(start_time, end_time)
885 self.draw_y_axis_with_labels() 885 self.draw_y_axis_with_labels()
886 886
887 def render_surface(self, sched, regions, selectable=False): 887 def render_surface(self, sched, regions, selectable=False):
888 raise NotImplementedError 888 raise NotImplementedError
889 889
890 def render_all(self, schedule): 890 def render_all(self, schedule):
891 raise NotImplementedError 891 raise NotImplementedError
892 892
893 def render_events(self, event_list): 893 def render_events(self, event_list):
894 for layer in Canvas.LAYERS: 894 for layer in Canvas.LAYERS:
895 prev_events = {} 895 prev_events = {}
896 for event in event_list: 896 for event in event_list:
897 event.render(self, layer, prev_events) 897 event.render(self, layer, prev_events)
898 898
899 def draw_axes(self, x_axis_label, y_axis_label): 899 def draw_axes(self, x_axis_label, y_axis_label):
900 """Draws and labels the axes according to the parameters that we were initialized 900 """Draws and labels the axes according to the parameters that we were initialized
901 with.""" 901 with."""
902 self.draw_grid_at_time(self.start_time, self.end_time, 0, len(self.attrs.y_item_list) - 1) 902 self.draw_grid_at_time(self.start_time, self.end_time, 0, len(self.attrs.y_item_list) - 1)
903 903
904 self.canvas.draw_x_axis(self.origin[0], self.origin[1], self.num_maj, self.attrs.maj_sep, self.attrs.min_per_maj) 904 self.canvas.draw_x_axis(self.origin[0], self.origin[1], self.num_maj, self.attrs.maj_sep, self.attrs.min_per_maj)
905 self.canvas.draw_y_axis(self.origin[0], self.origin[1], self._get_y_axis_height()) 905 self.canvas.draw_y_axis(self.origin[0], self.origin[1], self._get_y_axis_height())
906 self.canvas.draw_x_axis_labels(self.origin[0], self.origin[1], 0, self.num_maj - 1,\ 906 self.canvas.draw_x_axis_labels(self.origin[0], self.origin[1], 0, self.num_maj - 1,\
@@ -908,274 +908,274 @@ class Graph(object):
908 self.attrs.time_per_maj, self.attrs.show_min, self.attrs.majfopts, self.attrs.minfopts) 908 self.attrs.time_per_maj, self.attrs.show_min, self.attrs.majfopts, self.attrs.minfopts)
909 self.canvas.draw_y_axis_labels(self.origin[0], self.origin[1], self._get_y_axis_height(), self.y_item_list, \ 909 self.canvas.draw_y_axis_labels(self.origin[0], self.origin[1], self._get_y_axis_height(), self.y_item_list, \
910 self.attrs.y_item_size, self.attrs.item_fopts) 910 self.attrs.y_item_size, self.attrs.item_fopts)
911 911
912 def draw_grid_at_time(self, start_time, end_time, start_item, end_item): 912 def draw_grid_at_time(self, start_time, end_time, start_item, end_item):
913 """Draws the grid, but only in a certain time and item range.""" 913 """Draws the grid, but only in a certain time and item range."""
914 start_tick = max(0, self._get_bottom_tick(start_time)) 914 start_tick = max(0, self._get_bottom_tick(start_time))
915 end_tick = min(self.num_maj - 1, self._get_top_tick(end_time)) 915 end_tick = min(self.num_maj - 1, self._get_top_tick(end_time))
916 916
917 start_item = max(0, start_item) 917 start_item = max(0, start_item)
918 end_item = min(len(self.y_item_list), end_item) 918 end_item = min(len(self.y_item_list), end_item)
919 919
920 self.canvas.draw_grid(self.origin[0], self.origin[1], self._get_y_axis_height(), 920 self.canvas.draw_grid(self.origin[0], self.origin[1], self._get_y_axis_height(),
921 start_tick, end_tick, start_item, end_item, self.attrs.maj_sep, self.attrs.y_item_size, \ 921 start_tick, end_tick, start_item, end_item, self.attrs.maj_sep, self.attrs.y_item_size, \
922 self.attrs.min_per_maj, True) 922 self.attrs.min_per_maj, True)
923 923
924 def draw_x_axis_with_labels_at_time(self, start_time, end_time): 924 def draw_x_axis_with_labels_at_time(self, start_time, end_time):
925 start_tick = max(0, self._get_bottom_tick(start_time)) 925 start_tick = max(0, self._get_bottom_tick(start_time))
926 end_tick = min(self.num_maj - 1, self._get_top_tick(end_time)) 926 end_tick = min(self.num_maj - 1, self._get_top_tick(end_time))
927 927
928 self.canvas.draw_x_axis(self.origin[0], self.origin[1], start_tick, end_tick, \ 928 self.canvas.draw_x_axis(self.origin[0], self.origin[1], start_tick, end_tick, \
929 self.attrs.maj_sep, self.attrs.min_per_maj) 929 self.attrs.maj_sep, self.attrs.min_per_maj)
930 self.canvas.draw_x_axis_labels(self.origin[0], self.origin[1], start_tick, \ 930 self.canvas.draw_x_axis_labels(self.origin[0], self.origin[1], start_tick, \
931 end_tick, self.attrs.maj_sep, self.attrs.min_per_maj, 931 end_tick, self.attrs.maj_sep, self.attrs.min_per_maj,
932 self.start_time + start_tick * self.attrs.time_per_maj, 932 self.start_time + start_tick * self.attrs.time_per_maj,
933 self.attrs.time_per_maj, False) 933 self.attrs.time_per_maj, False)
934 934
935 def draw_y_axis_with_labels(self): 935 def draw_y_axis_with_labels(self):
936 self.canvas.draw_y_axis(self.origin[0], self.origin[1], self._get_y_axis_height()) 936 self.canvas.draw_y_axis(self.origin[0], self.origin[1], self._get_y_axis_height())
937 self.canvas.draw_y_axis_labels(self.origin[0], self.origin[1], self._get_y_axis_height(), \ 937 self.canvas.draw_y_axis_labels(self.origin[0], self.origin[1], self._get_y_axis_height(), \
938 self.y_item_list, self.attrs.y_item_size) 938 self.y_item_list, self.attrs.y_item_size)
939 939
940 def draw_suspend_triangle_at_time(self, time, task_no, cpu_no, selected=False): 940 def draw_suspend_triangle_at_time(self, time, task_no, cpu_no, selected=False):
941 """Draws a suspension symbol for a certain task at an instant in time.""" 941 """Draws a suspension symbol for a certain task at an instant in time."""
942 raise NotImplementedError 942 raise NotImplementedError
943 943
944 def add_sel_suspend_triangle_at_time(self, time, task_no, cpu_no, event): 944 def add_sel_suspend_triangle_at_time(self, time, task_no, cpu_no, event):
945 """Same as above, except instead of drawing adds a selectable region at 945 """Same as above, except instead of drawing adds a selectable region at
946 a certain time.""" 946 a certain time."""
947 raise NotImplementedError 947 raise NotImplementedError
948 948
949 def draw_resume_triangle_at_time(self, time, task_no, cpu_no, selected=False): 949 def draw_resume_triangle_at_time(self, time, task_no, cpu_no, selected=False):
950 """Draws a resumption symbol for a certain task at an instant in time.""" 950 """Draws a resumption symbol for a certain task at an instant in time."""
951 raise NotImplementedError 951 raise NotImplementedError
952 952
953 def add_sel_resume_triangle_at_time(self, time, task_no, cpu_no, event): 953 def add_sel_resume_triangle_at_time(self, time, task_no, cpu_no, event):
954 """Same as above, except instead of drawing adds a selectable region at 954 """Same as above, except instead of drawing adds a selectable region at
955 a certain time.""" 955 a certain time."""
956 raise NotImplementedError 956 raise NotImplementedError
957 957
958 def draw_completion_marker_at_time(self, time, task_no, cpu_no, selected=False): 958 def draw_completion_marker_at_time(self, time, task_no, cpu_no, selected=False):
959 """Draws a completion marker for a certain task at an instant in time.""" 959 """Draws a completion marker for a certain task at an instant in time."""
960 raise NotImplementedError 960 raise NotImplementedError
961 961
962 def add_sel_completion_marker_at_time(self, time, task_no, cpu_no, event): 962 def add_sel_completion_marker_at_time(self, time, task_no, cpu_no, event):
963 """Same as above, except instead of drawing adds a selectable region at 963 """Same as above, except instead of drawing adds a selectable region at
964 a certain time.""" 964 a certain time."""
965 raise NotImplementedError 965 raise NotImplementedError
966 966
967 def draw_release_arrow_at_time(self, time, task_no, job_no, selected=False): 967 def draw_release_arrow_at_time(self, time, task_no, job_no, selected=False):
968 """Draws a release arrow at a certain time for some task and job""" 968 """Draws a release arrow at a certain time for some task and job"""
969 raise NotImplementedError 969 raise NotImplementedError
970 970
971 def add_sel_release_arrow_at_time(self, time, task_no, event): 971 def add_sel_release_arrow_at_time(self, time, task_no, event):
972 """Same as above, except instead of drawing adds a selectable region at 972 """Same as above, except instead of drawing adds a selectable region at
973 a certain time.""" 973 a certain time."""
974 raise NotImplementedError 974 raise NotImplementedError
975 975
976 def draw_deadline_arrow_at_time(self, time, task_no, job_no, selected=False): 976 def draw_deadline_arrow_at_time(self, time, task_no, job_no, selected=False):
977 """Draws a deadline arrow at a certain time for some task and job""" 977 """Draws a deadline arrow at a certain time for some task and job"""
978 raise NotImplementedError 978 raise NotImplementedError
979 979
980 def add_sel_deadline_arrow_at_time(self, time, task_no, event): 980 def add_sel_deadline_arrow_at_time(self, time, task_no, event):
981 """Same as above, except instead of drawing adds a selectable region at 981 """Same as above, except instead of drawing adds a selectable region at
982 a certain time.""" 982 a certain time."""
983 raise NotImplementedError 983 raise NotImplementedError
984 984
985 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None): 985 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None):
986 """Draws a bar over a certain time period for some task, optionally labelling it.""" 986 """Draws a bar over a certain time period for some task, optionally labelling it."""
987 raise NotImplementedError 987 raise NotImplementedError
988 988
989 def add_sel_bar_at_time(self, start_time, end_time, task_no, cpu_no, event): 989 def add_sel_bar_at_time(self, start_time, end_time, task_no, cpu_no, event):
990 """Same as above, except instead of drawing adds a selectable region at 990 """Same as above, except instead of drawing adds a selectable region at
991 a certain time.""" 991 a certain time."""
992 raise NotImplementedError 992 raise NotImplementedError
993 993
994 def draw_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, clip_side=None, job_no=None): 994 def draw_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, clip_side=None, job_no=None):
995 """Draws a mini bar over a certain time period for some task, optionally labelling it.""" 995 """Draws a mini bar over a certain time period for some task, optionally labelling it."""
996 raise NotImplementedError 996 raise NotImplementedError
997 997
998 def add_sel_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, event): 998 def add_sel_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, event):
999 """Same as above, except instead of drawing adds a selectable region at 999 """Same as above, except instead of drawing adds a selectable region at
1000 a certain time.""" 1000 a certain time."""
1001 raise NotImplementedError 1001 raise NotImplementedError
1002 1002
1003class TaskGraph(Graph): 1003class TaskGraph(Graph):
1004 def render_surface(self, sched, regions, selectable=False): 1004 def render_surface(self, sched, regions, selectable=False):
1005 events_to_render = {} 1005 events_to_render = {}
1006 for layer in Canvas.LAYERS: 1006 for layer in Canvas.LAYERS:
1007 events_to_render[layer] = {} 1007 events_to_render[layer] = {}
1008 1008
1009 for region in regions: 1009 for region in regions:
1010 x, y, width, height = region 1010 x, y, width, height = region
1011 if not selectable: 1011 if not selectable:
1012 self.canvas.whiteout(x, y, width, height) 1012 self.canvas.whiteout(x, y, width, height)
1013 else: 1013 else:
1014 self.canvas.clear_selectable_regions(x, y, width, height) 1014 self.canvas.clear_selectable_regions(x, y, width, height)
1015 1015
1016 self.min_time, self.max_time, self.min_item, self.max_item = None, None, None, None 1016 self.min_time, self.max_time, self.min_item, self.max_item = None, None, None, None
1017 for region in regions: 1017 for region in regions:
1018 x, y, width, height = region 1018 x, y, width, height = region
1019 start_time, end_time, start_item, end_item = self.get_offset_params(x, y, width, height) 1019 start_time, end_time, start_item, end_item = self.get_offset_params(x, y, width, height)
1020 self._recomp_min_max(start_time, end_time, start_item, end_item) 1020 self._recomp_min_max(start_time, end_time, start_item, end_item)
1021 1021
1022 for event in sched.get_time_slot_array().iter_over_period( 1022 for event in sched.get_time_slot_array().iter_over_period(
1023 start_time, end_time, start_item, end_item, 1023 start_time, end_time, start_item, end_item,
1024 schedule.TimeSlotArray.TASK_LIST, schedule.EVENT_LIST): 1024 schedule.TimeSlotArray.TASK_LIST, schedule.EVENT_LIST):
1025 events_to_render[event.get_layer()][event] = None 1025 events_to_render[event.get_layer()][event] = None
1026 1026
1027 if not selectable: 1027 if not selectable:
1028 self.draw_skeleton(self.min_time, self.max_time, 1028 self.draw_skeleton(self.min_time, self.max_time,
1029 self.min_item, self.max_item) 1029 self.min_item, self.max_item)
1030 1030
1031 #if not selectable: 1031 #if not selectable:
1032 # for layer in events_to_render: 1032 # for layer in events_to_render:
1033 # print 'task render on layer', layer, ':', [str(e) for e in events_to_render[layer].keys()] 1033 # print 'task render on layer', layer, ':', [str(e) for e in events_to_render[layer].keys()]
1034 1034
1035 for layer in Canvas.LAYERS: 1035 for layer in Canvas.LAYERS:
1036 prev_events = {} 1036 prev_events = {}
1037 for event in events_to_render[layer]: 1037 for event in events_to_render[layer]:
1038 event.render(self, layer, prev_events, selectable) 1038 event.render(self, layer, prev_events, selectable)
1039 1039
1040 def draw_suspend_triangle_at_time(self, time, task_no, cpu_no, selected=False): 1040 def draw_suspend_triangle_at_time(self, time, task_no, cpu_no, selected=False):
1041 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR 1041 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR
1042 x = self._get_time_xpos(time) 1042 x = self._get_time_xpos(time)
1043 y = self._get_item_ypos(task_no) + self._get_bar_height() / 2.0 - height / 2.0 1043 y = self._get_item_ypos(task_no) + self._get_bar_height() / 2.0 - height / 2.0
1044 self.canvas.draw_suspend_triangle(x, y, height, selected) 1044 self.canvas.draw_suspend_triangle(x, y, height, selected)
1045 1045
1046 def add_sel_suspend_triangle_at_time(self, time, task_no, cpu_no, event): 1046 def add_sel_suspend_triangle_at_time(self, time, task_no, cpu_no, event):
1047 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR 1047 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR
1048 x = self._get_time_xpos(time) 1048 x = self._get_time_xpos(time)
1049 y = self._get_item_ypos(task_no) + self._get_bar_height() / 2.0 - height / 2.0 1049 y = self._get_item_ypos(task_no) + self._get_bar_height() / 2.0 - height / 2.0
1050 1050
1051 self.canvas.add_sel_suspend_triangle(x, y, height, event) 1051 self.canvas.add_sel_suspend_triangle(x, y, height, event)
1052 1052
1053 def draw_resume_triangle_at_time(self, time, task_no, cpu_no, selected=False): 1053 def draw_resume_triangle_at_time(self, time, task_no, cpu_no, selected=False):
1054 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR 1054 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR
1055 x = self._get_time_xpos(time) 1055 x = self._get_time_xpos(time)
1056 y = self._get_item_ypos(task_no) + self._get_bar_height() / 2.0 - height / 2.0 1056 y = self._get_item_ypos(task_no) + self._get_bar_height() / 2.0 - height / 2.0
1057 1057
1058 self.canvas.draw_resume_triangle(x, y, height, selected) 1058 self.canvas.draw_resume_triangle(x, y, height, selected)
1059 1059
1060 def add_sel_resume_triangle_at_time(self, time, task_no, cpu_no, event): 1060 def add_sel_resume_triangle_at_time(self, time, task_no, cpu_no, event):
1061 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR 1061 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR
1062 x = self._get_time_xpos(time) 1062 x = self._get_time_xpos(time)
1063 y = self._get_item_ypos(task_no) + self._get_bar_height() / 2.0 - height / 2.0 1063 y = self._get_item_ypos(task_no) + self._get_bar_height() / 2.0 - height / 2.0
1064 1064
1065 self.canvas.add_sel_resume_triangle(x, y, height, event) 1065 self.canvas.add_sel_resume_triangle(x, y, height, event)
1066 1066
1067 def draw_completion_marker_at_time(self, time, task_no, cpu_no, selected=False): 1067 def draw_completion_marker_at_time(self, time, task_no, cpu_no, selected=False):
1068 height = self._get_bar_height() * GraphFormat.COMPLETION_MARKER_FACTOR 1068 height = self._get_bar_height() * GraphFormat.COMPLETION_MARKER_FACTOR
1069 x = self._get_time_xpos(time) 1069 x = self._get_time_xpos(time)
1070 y = self._get_item_ypos(task_no) + self._get_bar_height() - height 1070 y = self._get_item_ypos(task_no) + self._get_bar_height() - height
1071 1071
1072 self.canvas.draw_completion_marker(x, y, height, selected) 1072 self.canvas.draw_completion_marker(x, y, height, selected)
1073 1073
1074 def add_sel_completion_marker_at_time(self, time, task_no, cpu_no, event): 1074 def add_sel_completion_marker_at_time(self, time, task_no, cpu_no, event):
1075 height = self._get_bar_height() * GraphFormat.COMPLETION_MARKER_FACTOR 1075 height = self._get_bar_height() * GraphFormat.COMPLETION_MARKER_FACTOR
1076 1076
1077 x = self._get_time_xpos(time) 1077 x = self._get_time_xpos(time)
1078 y = self._get_item_ypos(task_no) + self._get_bar_height() - height 1078 y = self._get_item_ypos(task_no) + self._get_bar_height() - height
1079 1079
1080 self.canvas.add_sel_completion_marker(x, y, height, event) 1080 self.canvas.add_sel_completion_marker(x, y, height, event)
1081 1081
1082 def draw_release_arrow_at_time(self, time, task_no, job_no=None, selected=False): 1082 def draw_release_arrow_at_time(self, time, task_no, job_no=None, selected=False):
1083 height = self._get_bar_height() * GraphFormat.BIG_ARROW_FACTOR 1083 height = self._get_bar_height() * GraphFormat.BIG_ARROW_FACTOR
1084 1084
1085 x = self._get_time_xpos(time) 1085 x = self._get_time_xpos(time)
1086 y = self._get_item_ypos(task_no) + self._get_bar_height() - height 1086 y = self._get_item_ypos(task_no) + self._get_bar_height() - height
1087 1087
1088 self.canvas.draw_release_arrow_big(x, y, height, selected) 1088 self.canvas.draw_release_arrow_big(x, y, height, selected)
1089 1089
1090 def add_sel_release_arrow_at_time(self, time, task_no, event): 1090 def add_sel_release_arrow_at_time(self, time, task_no, event):
1091 height = self._get_bar_height() * GraphFormat.BIG_ARROW_FACTOR 1091 height = self._get_bar_height() * GraphFormat.BIG_ARROW_FACTOR
1092 1092
1093 x = self._get_time_xpos(time) 1093 x = self._get_time_xpos(time)
1094 y = self._get_item_ypos(task_no) + self._get_bar_height() - height 1094 y = self._get_item_ypos(task_no) + self._get_bar_height() - height
1095 1095
1096 self.canvas.add_sel_release_arrow_big(x, y, height, event) 1096 self.canvas.add_sel_release_arrow_big(x, y, height, event)
1097 1097
1098 def draw_deadline_arrow_at_time(self, time, task_no, job_no=None, selected=False): 1098 def draw_deadline_arrow_at_time(self, time, task_no, job_no=None, selected=False):
1099 height = self._get_bar_height() * GraphFormat.BIG_ARROW_FACTOR 1099 height = self._get_bar_height() * GraphFormat.BIG_ARROW_FACTOR
1100 1100
1101 x = self._get_time_xpos(time) 1101 x = self._get_time_xpos(time)
1102 y = self._get_item_ypos(task_no) 1102 y = self._get_item_ypos(task_no)
1103 1103
1104 self.canvas.draw_deadline_arrow_big(x, y, height, selected) 1104 self.canvas.draw_deadline_arrow_big(x, y, height, selected)
1105 1105
1106 def add_sel_deadline_arrow_at_time(self, time, task_no, event): 1106 def add_sel_deadline_arrow_at_time(self, time, task_no, event):
1107 height = self._get_bar_height() * GraphFormat.BIG_ARROW_FACTOR 1107 height = self._get_bar_height() * GraphFormat.BIG_ARROW_FACTOR
1108 1108
1109 x = self._get_time_xpos(time) 1109 x = self._get_time_xpos(time)
1110 y = self._get_item_ypos(task_no) 1110 y = self._get_item_ypos(task_no)
1111 1111
1112 self.canvas.add_sel_deadline_arrow_big(x, y, height, event) 1112 self.canvas.add_sel_deadline_arrow_big(x, y, height, event)
1113 1113
1114 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False): 1114 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False):
1115 if start_time > end_time: 1115 if start_time > end_time:
1116 raise ValueError("Litmus is not a time machine") 1116 raise ValueError("Litmus is not a time machine")
1117 1117
1118 x = self._get_time_xpos(start_time) 1118 x = self._get_time_xpos(start_time)
1119 y = self._get_item_ypos(task_no) 1119 y = self._get_item_ypos(task_no)
1120 width = self._get_bar_width(start_time, end_time) 1120 width = self._get_bar_width(start_time, end_time)
1121 height = self._get_bar_height() 1121 height = self._get_bar_height()
1122 1122
1123 self.canvas.draw_bar(x, y, width, height, cpu_no, clip_side, selected) 1123 self.canvas.draw_bar(x, y, width, height, cpu_no, clip_side, selected)
1124 1124
1125 # if a job number is specified, we want to draw a superscript and subscript for the task and job number, respectively 1125 # if a job number is specified, we want to draw a superscript and subscript for the task and job number, respectively
1126 if job_no is not None: 1126 if job_no is not None:
1127 x += GraphFormat.BAR_LABEL_OFS 1127 x += GraphFormat.BAR_LABEL_OFS
1128 y += self.attrs.y_item_size * GraphFormat.BAR_SIZE_FACTOR / 2.0 1128 y += self.attrs.y_item_size * GraphFormat.BAR_SIZE_FACTOR / 2.0
1129 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \ 1129 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \
1130 GraphFormat.DEF_FOPTS_BAR, GraphFormat.DEF_FOPTS_BAR_SSCRIPT, AlignMode.LEFT, AlignMode.CENTER) 1130 GraphFormat.DEF_FOPTS_BAR, GraphFormat.DEF_FOPTS_BAR_SSCRIPT, AlignMode.LEFT, AlignMode.CENTER)
1131 1131
1132 def add_sel_bar_at_time(self, start_time, end_time, task_no, cpu_no, event): 1132 def add_sel_bar_at_time(self, start_time, end_time, task_no, cpu_no, event):
1133 if start_time > end_time: 1133 if start_time > end_time:
1134 raise ValueError("Litmus is not a time machine") 1134 raise ValueError("Litmus is not a time machine")
1135 1135
1136 x = self._get_time_xpos(start_time) 1136 x = self._get_time_xpos(start_time)
1137 y = self._get_item_ypos(task_no) 1137 y = self._get_item_ypos(task_no)
1138 width = self._get_bar_width(start_time, end_time) 1138 width = self._get_bar_width(start_time, end_time)
1139 height = self._get_bar_height() 1139 height = self._get_bar_height()
1140 1140
1141 self.canvas.add_sel_bar(x, y, width, height, event) 1141 self.canvas.add_sel_bar(x, y, width, height, event)
1142 1142
1143 def draw_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False): 1143 def draw_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False):
1144 if start_time > end_time: 1144 if start_time > end_time:
1145 raise ValueError("Litmus is not a time machine") 1145 raise ValueError("Litmus is not a time machine")
1146 1146
1147 x = self._get_time_xpos(start_time) 1147 x = self._get_time_xpos(start_time)
1148 y = self._get_item_ypos(task_no) - self._get_mini_bar_ofs() 1148 y = self._get_item_ypos(task_no) - self._get_mini_bar_ofs()
1149 width = self._get_bar_width(start_time, end_time) 1149 width = self._get_bar_width(start_time, end_time)
1150 height = self._get_mini_bar_height() 1150 height = self._get_mini_bar_height()
1151 1151
1152 self.canvas.draw_mini_bar(x, y, width, height, Canvas.NULL_PATTERN, clip_side, selected) 1152 self.canvas.draw_mini_bar(x, y, width, height, Canvas.NULL_PATTERN, clip_side, selected)
1153 1153
1154 if job_no is not None: 1154 if job_no is not None:
1155 x += GraphFormat.MINI_BAR_LABEL_OFS 1155 x += GraphFormat.MINI_BAR_LABEL_OFS
1156 y += self.attrs.y_item_size * GraphFormat.MINI_BAR_SIZE_FACTOR / 2.0 1156 y += self.attrs.y_item_size * GraphFormat.MINI_BAR_SIZE_FACTOR / 2.0
1157 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \ 1157 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \
1158 GraphFormat.DEF_FOPTS_MINI_BAR, GraphFormat.DEF_FOPTS_MINI_BAR_SSCRIPT, AlignMode.LEFT, AlignMode.CENTER) 1158 GraphFormat.DEF_FOPTS_MINI_BAR, GraphFormat.DEF_FOPTS_MINI_BAR_SSCRIPT, AlignMode.LEFT, AlignMode.CENTER)
1159 1159
1160 def add_sel_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, event): 1160 def add_sel_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, event):
1161 x = self._get_time_xpos(start_time) 1161 x = self._get_time_xpos(start_time)
1162 y = self._get_item_ypos(task_no) - self._get_mini_bar_ofs() 1162 y = self._get_item_ypos(task_no) - self._get_mini_bar_ofs()
1163 width = self._get_bar_width(start_time, end_time) 1163 width = self._get_bar_width(start_time, end_time)
1164 height = self._get_mini_bar_height() 1164 height = self._get_mini_bar_height()
1165 1165
1166 self.canvas.add_sel_mini_bar(x, y, width, height, event) 1166 self.canvas.add_sel_mini_bar(x, y, width, height, event)
1167 1167
1168class CpuGraph(Graph): 1168class CpuGraph(Graph):
1169 def render_surface(self, sched, regions, selectable=False): 1169 def render_surface(self, sched, regions, selectable=False):
1170 BOTTOM_EVENTS = [schedule.ReleaseEvent, schedule.DeadlineEvent, schedule.InversionStartEvent, 1170 BOTTOM_EVENTS = [schedule.ReleaseEvent, schedule.DeadlineEvent, schedule.InversionStartEvent,
1171 schedule.InversionEndEvent, schedule.InversionDummy] 1171 schedule.InversionEndEvent, schedule.InversionDummy]
1172 TOP_EVENTS = [schedule.SuspendEvent, schedule.ResumeEvent, schedule.CompleteEvent, 1172 TOP_EVENTS = [schedule.SuspendEvent, schedule.ResumeEvent, schedule.CompleteEvent,
1173 schedule.SwitchAwayEvent, schedule.SwitchToEvent, schedule.IsRunningDummy] 1173 schedule.SwitchAwayEvent, schedule.SwitchToEvent, schedule.IsRunningDummy]
1174 1174
1175 events_to_render = {} 1175 events_to_render = {}
1176 for layer in Canvas.LAYERS: 1176 for layer in Canvas.LAYERS:
1177 events_to_render[layer] = {} 1177 events_to_render[layer] = {}
1178 1178
1179 self.min_time, self.max_time, self.min_item, self.max_item = None, None, None, None 1179 self.min_time, self.max_time, self.min_item, self.max_item = None, None, None, None
1180 for region in regions: 1180 for region in regions:
1181 x, y, width, height = region 1181 x, y, width, height = region
@@ -1184,18 +1184,18 @@ class CpuGraph(Graph):
1184 self.canvas.whiteout(0, 0, self.canvas.surface.width, self.canvas.surface.height) 1184 self.canvas.whiteout(0, 0, self.canvas.surface.width, self.canvas.surface.height)
1185 else: 1185 else:
1186 self.canvas.clear_selectable_regions(x, y, width, height) 1186 self.canvas.clear_selectable_regions(x, y, width, height)
1187 1187
1188 for region in regions: 1188 for region in regions:
1189 x, y, width, height = region 1189 x, y, width, height = region
1190 start_time, end_time, start_item, end_item = self.get_offset_params(x, y, width, height) 1190 start_time, end_time, start_item, end_item = self.get_offset_params(x, y, width, height)
1191 self._recomp_min_max(start_time, end_time, start_item, end_item) 1191 self._recomp_min_max(start_time, end_time, start_item, end_item)
1192 1192
1193 for event in sched.get_time_slot_array().iter_over_period( 1193 for event in sched.get_time_slot_array().iter_over_period(
1194 start_time, end_time, start_item, end_item, 1194 start_time, end_time, start_item, end_item,
1195 schedule.TimeSlotArray.CPU_LIST, 1195 schedule.TimeSlotArray.CPU_LIST,
1196 TOP_EVENTS): 1196 TOP_EVENTS):
1197 events_to_render[event.get_layer()][event] = None 1197 events_to_render[event.get_layer()][event] = None
1198 1198
1199 if end_item >= len(self.y_item_list): 1199 if end_item >= len(self.y_item_list):
1200 # we are far down enough that we should render the releases and deadlines and inversions, 1200 # we are far down enough that we should render the releases and deadlines and inversions,
1201 # which appear near the x-axis 1201 # which appear near the x-axis
@@ -1205,136 +1205,136 @@ class CpuGraph(Graph):
1205 schedule.TimeSlotArray.CPU_LIST, 1205 schedule.TimeSlotArray.CPU_LIST,
1206 BOTTOM_EVENTS): 1206 BOTTOM_EVENTS):
1207 events_to_render[event.get_layer()][event] = None 1207 events_to_render[event.get_layer()][event] = None
1208 1208
1209 if not selectable: 1209 if not selectable:
1210 self.draw_skeleton(self.min_time, self.max_time, 1210 self.draw_skeleton(self.min_time, self.max_time,
1211 self.min_item, self.max_item) 1211 self.min_item, self.max_item)
1212 1212
1213 for layer in Canvas.LAYERS: 1213 for layer in Canvas.LAYERS:
1214 prev_events = {} 1214 prev_events = {}
1215 for event in events_to_render[layer]: 1215 for event in events_to_render[layer]:
1216 event.render(self, layer, prev_events, selectable) 1216 event.render(self, layer, prev_events, selectable)
1217 1217
1218 def render(self, schedule, start_time=None, end_time=None): 1218 def render(self, schedule, start_time=None, end_time=None):
1219 if end_time < start_time: 1219 if end_time < start_time:
1220 raise ValueError('start must be less than end') 1220 raise ValueError('start must be less than end')
1221 1221
1222 if start_time is None: 1222 if start_time is None:
1223 start_time = self.start 1223 start_time = self.start
1224 if end_time is None: 1224 if end_time is None:
1225 end_time = self.end 1225 end_time = self.end
1226 start_slot = self.get_time_slot(start_time) 1226 start_slot = self.get_time_slot(start_time)
1227 end_slot = min(len(self.time_slots), self.get_time_slot(end_time) + 1) 1227 end_slot = min(len(self.time_slots), self.get_time_slot(end_time) + 1)
1228 1228
1229 for layer in Canvas.LAYERS: 1229 for layer in Canvas.LAYERS:
1230 prev_events = {} 1230 prev_events = {}
1231 for i in range(start_slot, end_slot): 1231 for i in range(start_slot, end_slot):
1232 for event in self.time_slots[i]: 1232 for event in self.time_slots[i]:
1233 event.render(graph, layer, prev_events) 1233 event.render(graph, layer, prev_events)
1234 1234
1235 def draw_suspend_triangle_at_time(self, time, task_no, cpu_no, selected=False): 1235 def draw_suspend_triangle_at_time(self, time, task_no, cpu_no, selected=False):
1236 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR 1236 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR
1237 x = self._get_time_xpos(time) 1237 x = self._get_time_xpos(time)
1238 y = self._get_item_ypos(cpu_no) + self._get_bar_height() / 2.0 - height / 2.0 1238 y = self._get_item_ypos(cpu_no) + self._get_bar_height() / 2.0 - height / 2.0
1239 self.canvas.draw_suspend_triangle(x, y, height, selected) 1239 self.canvas.draw_suspend_triangle(x, y, height, selected)
1240 1240
1241 def add_sel_suspend_triangle_at_time(self, time, task_no, cpu_no, event): 1241 def add_sel_suspend_triangle_at_time(self, time, task_no, cpu_no, event):
1242 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR 1242 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR
1243 x = self._get_time_xpos(time) 1243 x = self._get_time_xpos(time)
1244 y = self._get_item_ypos(cpu_no) + self._get_bar_height() / 2.0 - height / 2.0 1244 y = self._get_item_ypos(cpu_no) + self._get_bar_height() / 2.0 - height / 2.0
1245 1245
1246 self.canvas.add_sel_suspend_triangle(x, y, height, event) 1246 self.canvas.add_sel_suspend_triangle(x, y, height, event)
1247 1247
1248 def draw_resume_triangle_at_time(self, time, task_no, cpu_no, selected=False): 1248 def draw_resume_triangle_at_time(self, time, task_no, cpu_no, selected=False):
1249 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR 1249 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR
1250 x = self._get_time_xpos(time) 1250 x = self._get_time_xpos(time)
1251 y = self._get_item_ypos(cpu_no) + self._get_bar_height() / 2.0 - height / 2.0 1251 y = self._get_item_ypos(cpu_no) + self._get_bar_height() / 2.0 - height / 2.0
1252 1252
1253 self.canvas.draw_resume_triangle(x, y, height, selected) 1253 self.canvas.draw_resume_triangle(x, y, height, selected)
1254 1254
1255 def add_sel_resume_triangle_at_time(self, time, task_no, cpu_no, event): 1255 def add_sel_resume_triangle_at_time(self, time, task_no, cpu_no, event):
1256 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR 1256 height = self._get_bar_height() * GraphFormat.BLOCK_TRIANGLE_FACTOR
1257 x = self._get_time_xpos(time) 1257 x = self._get_time_xpos(time)
1258 y = self._get_item_ypos(cpu_no) + self._get_bar_height() / 2.0 - height / 2.0 1258 y = self._get_item_ypos(cpu_no) + self._get_bar_height() / 2.0 - height / 2.0
1259 1259
1260 self.canvas.add_sel_resume_triangle(x, y, height, event) 1260 self.canvas.add_sel_resume_triangle(x, y, height, event)
1261 1261
1262 def draw_completion_marker_at_time(self, time, task_no, cpu_no, selected=False): 1262 def draw_completion_marker_at_time(self, time, task_no, cpu_no, selected=False):
1263 height = self._get_bar_height() * GraphFormat.COMPLETION_MARKER_FACTOR 1263 height = self._get_bar_height() * GraphFormat.COMPLETION_MARKER_FACTOR
1264 x = self._get_time_xpos(time) 1264 x = self._get_time_xpos(time)
1265 y = self._get_item_ypos(cpu_no) + self._get_bar_height() - height 1265 y = self._get_item_ypos(cpu_no) + self._get_bar_height() - height
1266 1266
1267 self.canvas.draw_completion_marker(x, y, height, selected) 1267 self.canvas.draw_completion_marker(x, y, height, selected)
1268 1268
1269 def add_sel_completion_marker_at_time(self, time, task_no, cpu_no, event): 1269 def add_sel_completion_marker_at_time(self, time, task_no, cpu_no, event):
1270 height = self._get_bar_height() * GraphFormat.COMPLETION_MARKER_FACTOR 1270 height = self._get_bar_height() * GraphFormat.COMPLETION_MARKER_FACTOR
1271 1271
1272 x = self._get_time_xpos(time) 1272 x = self._get_time_xpos(time)
1273 y = self._get_item_ypos(cpu_no) + self._get_bar_height() - height 1273 y = self._get_item_ypos(cpu_no) + self._get_bar_height() - height
1274 1274
1275 self.canvas.add_sel_completion_marker(x, y, height, event) 1275 self.canvas.add_sel_completion_marker(x, y, height, event)
1276 1276
1277 def draw_release_arrow_at_time(self, time, task_no, job_no=None, selected=False): 1277 def draw_release_arrow_at_time(self, time, task_no, job_no=None, selected=False):
1278 if job_no is None and task_no is not None: 1278 if job_no is None and task_no is not None:
1279 raise ValueError("Must specify a job number along with the task number") 1279 raise ValueError("Must specify a job number along with the task number")
1280 1280
1281 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR 1281 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR
1282 1282
1283 x = self._get_time_xpos(time) 1283 x = self._get_time_xpos(time)
1284 y = self.origin[1] - height 1284 y = self.origin[1] - height
1285 1285
1286 self.canvas.draw_release_arrow_small(x, y, height, selected) 1286 self.canvas.draw_release_arrow_small(x, y, height, selected)
1287 1287
1288 if task_no is not None: 1288 if task_no is not None:
1289 y -= GraphFormat.ARROW_LABEL_OFS 1289 y -= GraphFormat.ARROW_LABEL_OFS
1290 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \ 1290 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \
1291 GraphFormat.DEF_FOPTS_ARROW, GraphFormat.DEF_FOPTS_ARROW_SSCRIPT, \ 1291 GraphFormat.DEF_FOPTS_ARROW, GraphFormat.DEF_FOPTS_ARROW_SSCRIPT, \
1292 AlignMode.CENTER, AlignMode.BOTTOM) 1292 AlignMode.CENTER, AlignMode.BOTTOM)
1293 1293
1294 def add_sel_release_arrow_at_time(self, time, task_no, event): 1294 def add_sel_release_arrow_at_time(self, time, task_no, event):
1295 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR 1295 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR
1296 1296
1297 x = self._get_time_xpos(time) 1297 x = self._get_time_xpos(time)
1298 y = self.origin[1] - height 1298 y = self.origin[1] - height
1299 1299
1300 self.canvas.add_sel_release_arrow_small(x, y, height, event) 1300 self.canvas.add_sel_release_arrow_small(x, y, height, event)
1301 1301
1302 def draw_deadline_arrow_at_time(self, time, task_no, job_no=None, selected=False): 1302 def draw_deadline_arrow_at_time(self, time, task_no, job_no=None, selected=False):
1303 if job_no is None and task_no is not None: 1303 if job_no is None and task_no is not None:
1304 raise ValueError("Must specify a job number along with the task number") 1304 raise ValueError("Must specify a job number along with the task number")
1305 1305
1306 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR 1306 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR
1307 1307
1308 x = self._get_time_xpos(time) 1308 x = self._get_time_xpos(time)
1309 y = self.origin[1] - height 1309 y = self.origin[1] - height
1310 1310
1311 self.canvas.draw_deadline_arrow_small(x, y, height, selected) 1311 self.canvas.draw_deadline_arrow_small(x, y, height, selected)
1312 1312
1313 if task_no is not None: 1313 if task_no is not None:
1314 y -= GraphFormat.ARROW_LABEL_OFS 1314 y -= GraphFormat.ARROW_LABEL_OFS
1315 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \ 1315 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \
1316 GraphFormat.DEF_FOPTS_ARROW, GraphFormat.DEF_FOPTS_ARROW_SSCRIPT, \ 1316 GraphFormat.DEF_FOPTS_ARROW, GraphFormat.DEF_FOPTS_ARROW_SSCRIPT, \
1317 AlignMode.CENTER, AlignMode.BOTTOM) 1317 AlignMode.CENTER, AlignMode.BOTTOM)
1318 1318
1319 def add_sel_deadline_arrow_at_time(self, time, task_no, event): 1319 def add_sel_deadline_arrow_at_time(self, time, task_no, event):
1320 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR 1320 height = self._get_bar_height() * GraphFormat.SMALL_ARROW_FACTOR
1321 1321
1322 x = self._get_time_xpos(time) 1322 x = self._get_time_xpos(time)
1323 y = self.origin[1] - height 1323 y = self.origin[1] - height
1324 1324
1325 self.canvas.add_sel_deadline_arrow_small(x, y, height, event) 1325 self.canvas.add_sel_deadline_arrow_small(x, y, height, event)
1326 1326
1327 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False): 1327 def draw_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False):
1328 if start_time > end_time: 1328 if start_time > end_time:
1329 raise ValueError("Litmus is not a time machine") 1329 raise ValueError("Litmus is not a time machine")
1330 1330
1331 x = self._get_time_xpos(start_time) 1331 x = self._get_time_xpos(start_time)
1332 y = self._get_item_ypos(cpu_no) 1332 y = self._get_item_ypos(cpu_no)
1333 width = self._get_bar_width(start_time, end_time) 1333 width = self._get_bar_width(start_time, end_time)
1334 height = self._get_bar_height() 1334 height = self._get_bar_height()
1335 1335
1336 self.canvas.draw_bar(x, y, width, height, task_no, clip_side, selected) 1336 self.canvas.draw_bar(x, y, width, height, task_no, clip_side, selected)
1337 1337
1338 # if a job number is specified, we want to draw a superscript and subscript for the task and job number, respectively 1338 # if a job number is specified, we want to draw a superscript and subscript for the task and job number, respectively
1339 if job_no is not None: 1339 if job_no is not None:
1340 x += GraphFormat.BAR_LABEL_OFS 1340 x += GraphFormat.BAR_LABEL_OFS
@@ -1342,36 +1342,36 @@ class CpuGraph(Graph):
1342 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \ 1342 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \
1343 GraphFormat.DEF_FOPTS_BAR, GraphFormat.DEF_FOPTS_BAR_SSCRIPT, \ 1343 GraphFormat.DEF_FOPTS_BAR, GraphFormat.DEF_FOPTS_BAR_SSCRIPT, \
1344 AlignMode.LEFT, AlignMode.CENTER) 1344 AlignMode.LEFT, AlignMode.CENTER)
1345 1345
1346 def add_sel_bar_at_time(self, start_time, end_time, task_no, cpu_no, event): 1346 def add_sel_bar_at_time(self, start_time, end_time, task_no, cpu_no, event):
1347 x = self._get_time_xpos(start_time) 1347 x = self._get_time_xpos(start_time)
1348 y = self._get_item_ypos(cpu_no) 1348 y = self._get_item_ypos(cpu_no)
1349 width = self._get_bar_width(start_time, end_time) 1349 width = self._get_bar_width(start_time, end_time)
1350 height = self._get_bar_height() 1350 height = self._get_bar_height()
1351 1351
1352 self.canvas.add_sel_bar(x, y, width, height, event) 1352 self.canvas.add_sel_bar(x, y, width, height, event)
1353 1353
1354 def draw_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False): 1354 def draw_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, job_no=None, clip_side=None, selected=False):
1355 if start_time > end_time: 1355 if start_time > end_time:
1356 raise ValueError("Litmus is not a time machine") 1356 raise ValueError("Litmus is not a time machine")
1357 1357
1358 x = self._get_time_xpos(start_time) 1358 x = self._get_time_xpos(start_time)
1359 y = self._get_item_ypos(len(self.y_item_list)) 1359 y = self._get_item_ypos(len(self.y_item_list))
1360 width = self._get_bar_width(start_time, end_time) 1360 width = self._get_bar_width(start_time, end_time)
1361 height = self._get_mini_bar_height() 1361 height = self._get_mini_bar_height()
1362 1362
1363 self.canvas.draw_mini_bar(x, y, width, height, task_no, clip_side, selected) 1363 self.canvas.draw_mini_bar(x, y, width, height, task_no, clip_side, selected)
1364 1364
1365 if job_no is not None: 1365 if job_no is not None:
1366 x += GraphFormat.MINI_BAR_LABEL_OFS 1366 x += GraphFormat.MINI_BAR_LABEL_OFS
1367 y += self.attrs.y_item_size * GraphFormat.MINI_BAR_SIZE_FACTOR / 2.0 1367 y += self.attrs.y_item_size * GraphFormat.MINI_BAR_SIZE_FACTOR / 2.0
1368 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \ 1368 self.canvas.draw_label_with_sscripts('T', str(task_no), str(job_no), x, y, \
1369 GraphFormat.DEF_FOPTS_MINI_BAR, GraphFormat.DEF_FOPTS_MINI_BAR_SSCRIPT, AlignMode.LEFT, AlignMode.CENTER) 1369 GraphFormat.DEF_FOPTS_MINI_BAR, GraphFormat.DEF_FOPTS_MINI_BAR_SSCRIPT, AlignMode.LEFT, AlignMode.CENTER)
1370 1370
1371 def add_sel_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, event): 1371 def add_sel_mini_bar_at_time(self, start_time, end_time, task_no, cpu_no, event):
1372 x = self._get_time_xpos(start_time) 1372 x = self._get_time_xpos(start_time)
1373 y = self._get_item_ypos(len(self.y_item_list)) 1373 y = self._get_item_ypos(len(self.y_item_list))
1374 width = self._get_bar_width(start_time, end_time) 1374 width = self._get_bar_width(start_time, end_time)
1375 height = self._get_mini_bar_height() 1375 height = self._get_mini_bar_height()
1376 1376
1377 self.canvas.add_sel_mini_bar(x, y, width, height, event) 1377 self.canvas.add_sel_mini_bar(x, y, width, height, event)
diff --git a/unit_trace/viz/format.py b/unit_trace/viz/format.py
index 33e0b03..c544e26 100644
--- a/unit_trace/viz/format.py
+++ b/unit_trace/viz/format.py
@@ -13,41 +13,41 @@ class AlignMode(object):
13 LEFT = 0 13 LEFT = 0
14 CENTER = 1 14 CENTER = 1
15 RIGHT = 2 15 RIGHT = 2
16 16
17 BOTTOM = 3 17 BOTTOM = 3
18 TOP = 4 18 TOP = 4
19 19
20class GraphFormat(object): 20class GraphFormat(object):
21 """Container class for a bunch of optional and non-optional attributes to configure the appearance of the graph 21 """Container class for a bunch of optional and non-optional attributes to configure the appearance of the graph
22 (because it would be annoying to just have these all as raw arguments to the Graph constructor, and many people 22 (because it would be annoying to just have these all as raw arguments to the Graph constructor, and many people
23 probably don't care about most of them anyway).""" 23 probably don't care about most of them anyway)."""
24 24
25 GRID_COLOR = (0.7, 0.7, 0.7) 25 GRID_COLOR = (0.7, 0.7, 0.7)
26 HIGHLIGHT_COLOR = (0.85, 0.0, 0.0) 26 HIGHLIGHT_COLOR = (0.85, 0.0, 0.0)
27 BORDER_COLOR = (0.0, 0.0, 0.0) 27 BORDER_COLOR = (0.0, 0.0, 0.0)
28 LITE_BORDER_COLOR = (0.4, 0.4, 0.4) 28 LITE_BORDER_COLOR = (0.4, 0.4, 0.4)
29 29
30 BORDER_THICKNESS = 1 30 BORDER_THICKNESS = 1
31 GRID_THICKNESS = 1 31 GRID_THICKNESS = 1
32 AXIS_THICKNESS = 1 32 AXIS_THICKNESS = 1
33 33
34 BAND_THICKNESS = 1.5 34 BAND_THICKNESS = 1.5
35 BAND_COLOR = (0.85, 0.0, 0.0) 35 BAND_COLOR = (0.85, 0.0, 0.0)
36 36
37 X_AXIS_MEASURE_OFS = 30 37 X_AXIS_MEASURE_OFS = 30
38 X_AXIS_LABEL_GAP = 10 38 X_AXIS_LABEL_GAP = 10
39 Y_AXIS_ITEM_GAP = 10 39 Y_AXIS_ITEM_GAP = 10
40 MAJ_TICK_SIZE = 20 40 MAJ_TICK_SIZE = 20
41 MIN_TICK_SIZE = 12 41 MIN_TICK_SIZE = 12
42 42
43 BIG_ARROWHEAD_FACTOR = 0.2 43 BIG_ARROWHEAD_FACTOR = 0.2
44 SMALL_ARROWHEAD_FACTOR = 0.3 44 SMALL_ARROWHEAD_FACTOR = 0.3
45 TEE_FACTOR = 0.3 45 TEE_FACTOR = 0.3
46 46
47 DEF_FOPTS_LABEL = FontOptions("Times", 16, (0.0, 0.0, 0.0)) 47 DEF_FOPTS_LABEL = FontOptions("Times", 16, (0.0, 0.0, 0.0))
48 DEF_FOPTS_LABEL_SSCRIPT = FontOptions("Times", 8, (0.0, 0.0, 0.0)) 48 DEF_FOPTS_LABEL_SSCRIPT = FontOptions("Times", 8, (0.0, 0.0, 0.0))
49 DEF_FOPTS_MAJ = FontOptions("Times", 14, (0.1, 0.1, 0.1)) 49 DEF_FOPTS_MAJ = FontOptions("Times", 14, (0.1, 0.1, 0.1))
50 DEF_FOPTS_MIN = FontOptions("Times", 9, (0.1, 0.1, 0.1)) 50 DEF_FOPTS_MIN = FontOptions("Times", 9, (0.1, 0.1, 0.1))
51 DEF_FOPTS_ITEM = FontOptions("Times", 20, (0.0, 0.5, 0.1)) 51 DEF_FOPTS_ITEM = FontOptions("Times", 20, (0.0, 0.5, 0.1))
52 DEF_FOPTS_BAR = FontOptions("Times", 14, (0.0, 0.0, 0.0)) 52 DEF_FOPTS_BAR = FontOptions("Times", 14, (0.0, 0.0, 0.0))
53 DEF_FOPTS_BAR_SSCRIPT = FontOptions("Times", 7, (0.0, 0.0, 0.0)) 53 DEF_FOPTS_BAR_SSCRIPT = FontOptions("Times", 7, (0.0, 0.0, 0.0))
@@ -55,31 +55,31 @@ class GraphFormat(object):
55 DEF_FOPTS_MINI_BAR_SSCRIPT = FontOptions("Times", 7, (0.0, 0.0, 0.0)) 55 DEF_FOPTS_MINI_BAR_SSCRIPT = FontOptions("Times", 7, (0.0, 0.0, 0.0))
56 DEF_FOPTS_ARROW = FontOptions("Times", 12, (0.0, 0.0, 0.0)) 56 DEF_FOPTS_ARROW = FontOptions("Times", 12, (0.0, 0.0, 0.0))
57 DEF_FOPTS_ARROW_SSCRIPT = FontOptions("Times", 7, (0.0, 0.0, 0.0)) 57 DEF_FOPTS_ARROW_SSCRIPT = FontOptions("Times", 7, (0.0, 0.0, 0.0))
58 58
59 LEFT_SIDE_PAD = 30 59 LEFT_SIDE_PAD = 30
60 WIDTH_PAD = 50 60 WIDTH_PAD = 50
61 HEIGHT_PAD = 150 61 HEIGHT_PAD = 150
62 Y_ITEM_PAD_FACTOR = 0.5 62 Y_ITEM_PAD_FACTOR = 0.5
63 63
64 DEF_TIME_PER_MAJ = 10 64 DEF_TIME_PER_MAJ = 10
65 DEF_MAJ_SEP = 200 65 DEF_MAJ_SEP = 200
66 DEF_MIN_PER_MAJ = 5 66 DEF_MIN_PER_MAJ = 5
67 DEF_Y_ITEM_SIZE = 50 67 DEF_Y_ITEM_SIZE = 50
68 68
69 AXIS_LABEL_VERT_OFS = 30 69 AXIS_LABEL_VERT_OFS = 30
70 BAR_SIZE_FACTOR = 0.4 70 BAR_SIZE_FACTOR = 0.4
71 MINI_BAR_SIZE_FACTOR = 0.2 71 MINI_BAR_SIZE_FACTOR = 0.2
72 BAR_MINI_BAR_GAP_FACTOR = 0.1 72 BAR_MINI_BAR_GAP_FACTOR = 0.1
73 73
74 BAR_LABEL_OFS = 2 74 BAR_LABEL_OFS = 2
75 MINI_BAR_LABEL_OFS = 1 75 MINI_BAR_LABEL_OFS = 1
76 ARROW_LABEL_OFS = 2 76 ARROW_LABEL_OFS = 2
77 77
78 BLOCK_TRIANGLE_FACTOR = 0.7 78 BLOCK_TRIANGLE_FACTOR = 0.7
79 BIG_ARROW_FACTOR = 1.6 79 BIG_ARROW_FACTOR = 1.6
80 SMALL_ARROW_FACTOR = 0.6 80 SMALL_ARROW_FACTOR = 0.6
81 COMPLETION_MARKER_FACTOR = 1.6 81 COMPLETION_MARKER_FACTOR = 1.6
82 82
83 def __init__(self, time_per_maj=DEF_TIME_PER_MAJ, maj_sep=DEF_MAJ_SEP, \ 83 def __init__(self, time_per_maj=DEF_TIME_PER_MAJ, maj_sep=DEF_MAJ_SEP, \
84 min_per_maj=DEF_MIN_PER_MAJ, y_item_size=DEF_Y_ITEM_SIZE, bar_fopts=DEF_FOPTS_BAR, \ 84 min_per_maj=DEF_MIN_PER_MAJ, y_item_size=DEF_Y_ITEM_SIZE, bar_fopts=DEF_FOPTS_BAR, \
85 item_fopts=DEF_FOPTS_ITEM, show_min=False, majfopts=DEF_FOPTS_MAJ, \ 85 item_fopts=DEF_FOPTS_ITEM, show_min=False, majfopts=DEF_FOPTS_MAJ, \
diff --git a/unit_trace/viz/renderer.py b/unit_trace/viz/renderer.py
index d94129c..46c6628 100644
--- a/unit_trace/viz/renderer.py
+++ b/unit_trace/viz/renderer.py
@@ -4,17 +4,17 @@ from draw import *
4 4
5"""The renderer, a glue object which converts a schedule to its representation 5"""The renderer, a glue object which converts a schedule to its representation
6on a graph.""" 6on a graph."""
7 7
8class Renderer(object): 8class Renderer(object):
9 def __init__(self, schedule): 9 def __init__(self, schedule):
10 self.schedule = schedule 10 self.schedule = schedule
11 11
12 def prepare_task_graph(self, SurfaceType=ImageSurface, attrs=GraphFormat()): 12 def prepare_task_graph(self, SurfaceType=ImageSurface, attrs=GraphFormat()):
13 """Outputs the fully-rendered graph (y-axis = tasks) to a Cairo ImageSurface""" 13 """Outputs the fully-rendered graph (y-axis = tasks) to a Cairo ImageSurface"""
14 item_list = self.get_task_item_list() 14 item_list = self.get_task_item_list()
15 start, end = self.schedule.get_time_bounds() 15 start, end = self.schedule.get_time_bounds()
16 self.graph = TaskGraph(CairoCanvas, SurfaceType(), start, end, item_list, attrs) 16 self.graph = TaskGraph(CairoCanvas, SurfaceType(), start, end, item_list, attrs)
17 17
18 def prepare_cpu_graph(self, SurfaceType=ImageSurface, attrs=GraphFormat()): 18 def prepare_cpu_graph(self, SurfaceType=ImageSurface, attrs=GraphFormat()):
19 item_list = ['CPU %d' % i for i in range(0, self.schedule.get_num_cpus())] 19 item_list = ['CPU %d' % i for i in range(0, self.schedule.get_num_cpus())]
20 start, end = self.schedule.get_time_bounds() 20 start, end = self.schedule.get_time_bounds()
@@ -25,16 +25,16 @@ class Renderer(object):
25 and drawing it piece by piece""" 25 and drawing it piece by piece"""
26 #graph.draw_axes('Time', '') 26 #graph.draw_axes('Time', '')
27 self.schedule.render(self.graph) 27 self.schedule.render(self.graph)
28 28
29 def write_out(self, fname): 29 def write_out(self, fname):
30 self.graph.surface.write_out(fname) 30 self.graph.surface.write_out(fname)
31 31
32 def get_graph(self): 32 def get_graph(self):
33 return self.graph 33 return self.graph
34 34
35 def get_schedule(self): 35 def get_schedule(self):
36 return self.schedule 36 return self.schedule
37 37
38 def get_task_item_list(self): 38 def get_task_item_list(self):
39 return [task.get_name() for task in self.schedule.get_task_list()] 39 return [task.get_name() for task in self.schedule.get_task_list()]
40 40
diff --git a/unit_trace/viz/schedule.py b/unit_trace/viz/schedule.py
index f134562..71f42ec 100644
--- a/unit_trace/viz/schedule.py
+++ b/unit_trace/viz/schedule.py
@@ -18,19 +18,19 @@ class TimeSlotArray(object):
18 the (approximate) time at which they occur. Events that occur at approximately the same 18 the (approximate) time at which they occur. Events that occur at approximately the same
19 time are assigned the same ``slot'', and each slot organizes its events by task number 19 time are assigned the same ``slot'', and each slot organizes its events by task number
20 as well as by CPU.""" 20 as well as by CPU."""
21 21
22 TASK_LIST = 0 22 TASK_LIST = 0
23 CPU_LIST = 1 23 CPU_LIST = 1
24 24
25 def __init__(self, time_per_maj=None, num_tasks=0, num_cpus=0): 25 def __init__(self, time_per_maj=None, num_tasks=0, num_cpus=0):
26 if time_per_maj is None: 26 if time_per_maj is None:
27 self.array = None 27 self.array = None
28 return 28 return
29 29
30 self.time_per_maj = time_per_maj 30 self.time_per_maj = time_per_maj
31 self.list_sizes = { TimeSlotArray.TASK_LIST : num_tasks, TimeSlotArray.CPU_LIST : num_cpus } 31 self.list_sizes = { TimeSlotArray.TASK_LIST : num_tasks, TimeSlotArray.CPU_LIST : num_cpus }
32 self.array = {} 32 self.array = {}
33 33
34 for type in self.list_sizes: 34 for type in self.list_sizes:
35 num = self.list_sizes[type] 35 num = self.list_sizes[type]
36 self.array[type] = [] 36 self.array[type] = []
@@ -40,26 +40,26 @@ class TimeSlotArray(object):
40 # by task). 40 # by task).
41 self.array[type].append(dict(zip(EVENT_LIST, \ 41 self.array[type].append(dict(zip(EVENT_LIST, \
42 [{} for j in range(0, len(EVENT_LIST))]))) 42 [{} for j in range(0, len(EVENT_LIST))])))
43 43
44 def get_time_slot(self, time): 44 def get_time_slot(self, time):
45 return int(time // self.time_per_maj) 45 return int(time // self.time_per_maj)
46 46
47 def _put_event_in_slot(self, list_type, no, klass, slot, event): 47 def _put_event_in_slot(self, list_type, no, klass, slot, event):
48 if slot not in self.array[list_type][no][klass]: 48 if slot not in self.array[list_type][no][klass]:
49 self.array[list_type][no][klass][slot] = [] 49 self.array[list_type][no][klass][slot] = []
50 self.array[list_type][no][klass][slot].append(event) 50 self.array[list_type][no][klass][slot].append(event)
51 51
52 def add_event_to_time_slot(self, event): 52 def add_event_to_time_slot(self, event):
53 task_no = event.get_job().get_task().get_task_no() 53 task_no = event.get_job().get_task().get_task_no()
54 cpu = event.get_cpu() 54 cpu = event.get_cpu()
55 time_slot = self.get_time_slot(event.get_time()) 55 time_slot = self.get_time_slot(event.get_time())
56 56
57 self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, event.__class__, time_slot, event) 57 self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, event.__class__, time_slot, event)
58 self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, event.__class__, time_slot, event) 58 self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, event.__class__, time_slot, event)
59 59
60 if event.__class__ in SPAN_END_EVENTS: 60 if event.__class__ in SPAN_END_EVENTS:
61 self.fill_span_event_from_end(event) 61 self.fill_span_event_from_end(event)
62 62
63 def fill_span_event_from_end(self, event): 63 def fill_span_event_from_end(self, event):
64 start_slot = None 64 start_slot = None
65 if event.corresp_start_event is None: 65 if event.corresp_start_event is None:
@@ -67,18 +67,18 @@ class TimeSlotArray(object):
67 else: 67 else:
68 start_slot = self.get_time_slot(event.corresp_start_event.get_time()) 68 start_slot = self.get_time_slot(event.corresp_start_event.get_time())
69 end_slot = self.get_time_slot(event.get_time()) 69 end_slot = self.get_time_slot(event.get_time())
70 70
71 for slot in range(start_slot + 1, end_slot): 71 for slot in range(start_slot + 1, end_slot):
72 task_no = event.get_job().get_task().get_task_no() 72 task_no = event.get_job().get_task().get_task_no()
73 cpu = event.get_cpu() 73 cpu = event.get_cpu()
74 74
75 dummy = SPAN_END_EVENTS[event.__class__](task_no, cpu) 75 dummy = SPAN_END_EVENTS[event.__class__](task_no, cpu)
76 dummy.corresp_start_event = event.corresp_start_event 76 dummy.corresp_start_event = event.corresp_start_event
77 dummy.corresp_end_event = event 77 dummy.corresp_end_event = event
78 78
79 self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, dummy.__class__, slot, dummy) 79 self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, dummy.__class__, slot, dummy)
80 self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, dummy.__class__, slot, dummy) 80 self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, dummy.__class__, slot, dummy)
81 81
82 def fill_span_event_from_start(self, event): 82 def fill_span_event_from_start(self, event):
83 end_slot = None 83 end_slot = None
84 if event.corresp_end_event is None: 84 if event.corresp_end_event is None:
@@ -86,44 +86,44 @@ class TimeSlotArray(object):
86 else: 86 else:
87 end_slot = self.get_time_slot(event.corresp_end_event.get_time()) 87 end_slot = self.get_time_slot(event.corresp_end_event.get_time())
88 start_slot = self.get_time_slot(event.get_time()) 88 start_slot = self.get_time_slot(event.get_time())
89 89
90 for slot in range(start_slot + 1, end_slot): 90 for slot in range(start_slot + 1, end_slot):
91 task_no = event.get_job().get_task().get_task_no() 91 task_no = event.get_job().get_task().get_task_no()
92 cpu = event.get_cpu() 92 cpu = event.get_cpu()
93 93
94 dummy = SPAN_START_EVENTS[event.__class__](task_no, cpu) 94 dummy = SPAN_START_EVENTS[event.__class__](task_no, cpu)
95 dummy.corresp_start_event = event 95 dummy.corresp_start_event = event
96 dummy.corresp_end_event = event.corresp_end_event 96 dummy.corresp_end_event = event.corresp_end_event
97 97
98 self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, dummy.__class__, slot, dummy) 98 self._put_event_in_slot(TimeSlotArray.TASK_LIST, task_no, dummy.__class__, slot, dummy)
99 self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, dummy.__class__, slot, dummy) 99 self._put_event_in_slot(TimeSlotArray.CPU_LIST, cpu, dummy.__class__, slot, dummy)
100 100
101 def iter_over_period(self, start, end, start_no, end_no, list_type, event_types): 101 def iter_over_period(self, start, end, start_no, end_no, list_type, event_types):
102 if self.array is None: 102 if self.array is None:
103 return # empty schedule 103 return # empty schedule
104 104
105 if start > end: 105 if start > end:
106 raise ValueError('Litmus is not a time machine') 106 raise ValueError('Litmus is not a time machine')
107 if start_no > end_no: 107 if start_no > end_no:
108 raise ValueError('start no should be less than end no') 108 raise ValueError('start no should be less than end no')
109 109
110 start_slot = self.get_time_slot(start) 110 start_slot = self.get_time_slot(start)
111 end_slot = self.get_time_slot(end) + 2 111 end_slot = self.get_time_slot(end) + 2
112 112
113 start_no = max(0, start_no) 113 start_no = max(0, start_no)
114 end_no = min(self.list_sizes[list_type] - 1, end_no) 114 end_no = min(self.list_sizes[list_type] - 1, end_no)
115 115
116 for no in range(start_no, end_no + 1): 116 for no in range(start_no, end_no + 1):
117 for type in event_types: 117 for type in event_types:
118 for slot in range(start_slot, end_slot): 118 for slot in range(start_slot, end_slot):
119 if slot in self.array[list_type][no][type]: 119 if slot in self.array[list_type][no][type]:
120 for event in self.array[list_type][no][type][slot]: 120 for event in self.array[list_type][no][type][slot]:
121 yield event 121 yield event
122 122
123class Schedule(object): 123class Schedule(object):
124 """The total schedule (task system), consisting of a certain number of 124 """The total schedule (task system), consisting of a certain number of
125 tasks.""" 125 tasks."""
126 126
127 def __init__(self, name, num_cpus, task_list=[]): 127 def __init__(self, name, num_cpus, task_list=[]):
128 self.name = name 128 self.name = name
129 self.tasks = {} 129 self.tasks = {}
@@ -134,41 +134,41 @@ class Schedule(object):
134 self.num_cpus = num_cpus 134 self.num_cpus = num_cpus
135 for task in task_list: 135 for task in task_list:
136 self.add_task(task) 136 self.add_task(task)
137 137
138 def get_selected(self): 138 def get_selected(self):
139 return self.selected 139 return self.selected
140 140
141 def set_selected(self, new_selected): 141 def set_selected(self, new_selected):
142 for event in self.selected: 142 for event in self.selected:
143 event.selected = False 143 event.selected = False
144 for event in new_selected: 144 for event in new_selected:
145 event.selected = True 145 event.selected = True
146 self.selected = new_selected 146 self.selected = new_selected
147 147
148 def get_selected(self): 148 def get_selected(self):
149 return copy.copy(self.selected) 149 return copy.copy(self.selected)
150 150
151 def set_time_params(self, time_per_maj=None): 151 def set_time_params(self, time_per_maj=None):
152 self.time_per_maj = time_per_maj 152 self.time_per_maj = time_per_maj
153 if self.time_per_maj is None: 153 if self.time_per_maj is None:
154 self.time_slot_array = TimeSlotArray() 154 self.time_slot_array = TimeSlotArray()
155 return 155 return
156 156
157 self.time_slot_array = TimeSlotArray(self.time_per_maj, \ 157 self.time_slot_array = TimeSlotArray(self.time_per_maj, \
158 len(self.task_list), self.num_cpus) 158 len(self.task_list), self.num_cpus)
159 159
160 def get_time_slot_array(self): 160 def get_time_slot_array(self):
161 return self.time_slot_array 161 return self.time_slot_array
162 162
163 def get_time_bounds(self): 163 def get_time_bounds(self):
164 return (self.start, self.end) 164 return (self.start, self.end)
165 165
166 def scan(self, time_per_maj): 166 def scan(self, time_per_maj):
167 self.start = None 167 self.start = None
168 self.end = None 168 self.end = None
169 169
170 self.set_time_params(time_per_maj) 170 self.set_time_params(time_per_maj)
171 171
172 # we scan the graph task by task, and job by job 172 # we scan the graph task by task, and job by job
173 for task_no, task in enumerate(self.get_task_list()): 173 for task_no, task in enumerate(self.get_task_list()):
174 switches = {} 174 switches = {}
@@ -176,12 +176,12 @@ class Schedule(object):
176 switches[event] = None 176 switches[event] = None
177 cur_cpu = [Event.NO_CPU] 177 cur_cpu = [Event.NO_CPU]
178 for job_no in sorted(task.get_jobs().keys()): 178 for job_no in sorted(task.get_jobs().keys()):
179 job = task.get_jobs()[job_no] 179 job = task.get_jobs()[job_no]
180 for event_time in sorted(job.get_events().keys()): 180 for event_time in sorted(job.get_events().keys()):
181 # could have multiple events at the same time (unlikely but possible) 181 # could have multiple events at the same time (unlikely but possible)
182 for event in job.get_events()[event_time]: 182 for event in job.get_events()[event_time]:
183 event.scan(cur_cpu, switches) 183 event.scan(cur_cpu, switches)
184 184
185 # What if one of the initial "span events" (switch to or inversion starting) never got a 185 # What if one of the initial "span events" (switch to or inversion starting) never got a
186 # corresponding end event? Well, then we assume that the end event was simply outside of 186 # corresponding end event? Well, then we assume that the end event was simply outside of
187 # the range of whatever we read in. So we need to fill dummies starting from the initial 187 # the range of whatever we read in. So we need to fill dummies starting from the initial
@@ -191,7 +191,7 @@ class Schedule(object):
191 event = switches[span_event] 191 event = switches[span_event]
192 if event is not None: 192 if event is not None:
193 self.time_slot_array.fill_span_event_from_start(event) 193 self.time_slot_array.fill_span_event_from_start(event)
194 194
195 def add_task(self, task): 195 def add_task(self, task):
196 if task.name in self.tasks: 196 if task.name in self.tasks:
197 raise ValueError("task already in list!") 197 raise ValueError("task already in list!")
@@ -200,23 +200,23 @@ class Schedule(object):
200 task.schedule = self 200 task.schedule = self
201 task.task_no = self.cur_task_no 201 task.task_no = self.cur_task_no
202 self.cur_task_no += 1 202 self.cur_task_no += 1
203 203
204 def get_tasks(self): 204 def get_tasks(self):
205 return self.tasks 205 return self.tasks
206 206
207 def get_task_list(self): 207 def get_task_list(self):
208 return self.task_list 208 return self.task_list
209 209
210 def get_name(self): 210 def get_name(self):
211 return self.name 211 return self.name
212 212
213 def get_num_cpus(self): 213 def get_num_cpus(self):
214 return self.num_cpus 214 return self.num_cpus
215 215
216class Task(object): 216class Task(object):
217 """Represents a task, including the set of jobs that were run under 217 """Represents a task, including the set of jobs that were run under
218 this task.""" 218 this task."""
219 219
220 def __init__(self, name, job_list=[]): 220 def __init__(self, name, job_list=[]):
221 self.name = name 221 self.name = name
222 self.jobs = {} 222 self.jobs = {}
@@ -224,25 +224,25 @@ class Task(object):
224 self.schedule = None 224 self.schedule = None
225 for job in job_list: 225 for job in job_list:
226 self.add_job(job) 226 self.add_job(job)
227 227
228 def add_job(self, job): 228 def add_job(self, job):
229 if job.job_no in self.jobs: 229 if job.job_no in self.jobs:
230 raise ScheduleError("a job is already being released at this time for this task") 230 raise ScheduleError("a job is already being released at this time for this task")
231 self.jobs[job.job_no] = job 231 self.jobs[job.job_no] = job
232 job.task = self 232 job.task = self
233 233
234 def get_schedule(self): 234 def get_schedule(self):
235 return self.schedule 235 return self.schedule
236 236
237 def get_jobs(self): 237 def get_jobs(self):
238 return self.jobs 238 return self.jobs
239 239
240 def get_task_no(self): 240 def get_task_no(self):
241 return self.task_no 241 return self.task_no
242 242
243 def get_name(self): 243 def get_name(self):
244 return self.name 244 return self.name
245 245
246class Job(object): 246class Job(object):
247 """Represents a job, including everything that happens related to the job""" 247 """Represents a job, including everything that happens related to the job"""
248 def __init__(self, job_no, event_list=[]): 248 def __init__(self, job_no, event_list=[]):
@@ -251,19 +251,19 @@ class Job(object):
251 self.task = None 251 self.task = None
252 for event in event_list: 252 for event in event_list:
253 self.add_event(event) 253 self.add_event(event)
254 254
255 def add_event(self, event): 255 def add_event(self, event):
256 if event.time not in self.events: 256 if event.time not in self.events:
257 self.events[event.time] = [] 257 self.events[event.time] = []
258 self.events[event.time].append(event) 258 self.events[event.time].append(event)
259 event.job = self 259 event.job = self
260 260
261 def get_events(self): 261 def get_events(self):
262 return self.events 262 return self.events
263 263
264 def get_task(self): 264 def get_task(self):
265 return self.task 265 return self.task
266 266
267 def get_job_no(self): 267 def get_job_no(self):
268 return self.job_no 268 return self.job_no
269 269
@@ -279,61 +279,61 @@ class DummyEvent(object):
279 self.cpu = cpu 279 self.cpu = cpu
280 self.job = None 280 self.job = None
281 self.layer = None 281 self.layer = None
282 282
283 def __str__(self): 283 def __str__(self):
284 return '[Dummy Event]' 284 return '[Dummy Event]'
285 285
286 def get_time(self): 286 def get_time(self):
287 return self.time 287 return self.time
288 288
289 def get_cpu(self): 289 def get_cpu(self):
290 return self.cpu 290 return self.cpu
291 291
292 def get_job(self): 292 def get_job(self):
293 return self.job 293 return self.job
294 294
295 def get_layer(self): 295 def get_layer(self):
296 return self.layer 296 return self.layer
297 297
298 def render(self, graph, layer, prev_events, selectable=False): 298 def render(self, graph, layer, prev_events, selectable=False):
299 """Method that the visualizer calls to tell the event to render itself 299 """Method that the visualizer calls to tell the event to render itself
300 Obviously only implemented by subclasses (actual event types) 300 Obviously only implemented by subclasses (actual event types)
301 301
302 ``Rendering'' can mean either actually drawing the event or just 302 ``Rendering'' can mean either actually drawing the event or just
303 adding it as a selectable region. This is controlled by the 303 adding it as a selectable region. This is controlled by the
304 ``selectable'' parameter""" 304 ``selectable'' parameter"""
305 raise NotImplementdError 305 raise NotImplementdError
306 306
307class Event(DummyEvent): 307class Event(DummyEvent):
308 """Represents an event that occurs while a job is running (e.g. get scheduled 308 """Represents an event that occurs while a job is running (e.g. get scheduled
309 on a CPU, block, ...)""" 309 on a CPU, block, ...)"""
310 NO_CPU = -1 310 NO_CPU = -1
311 NUM_DEC_PLACES = 2 311 NUM_DEC_PLACES = 2
312 312
313 def __init__(self, time, cpu): 313 def __init__(self, time, cpu):
314 super(Event, self).__init__(time, cpu) 314 super(Event, self).__init__(time, cpu)
315 self.erroneous = False 315 self.erroneous = False
316 self.selected = False 316 self.selected = False
317 317
318 def __str__(self): 318 def __str__(self):
319 return '[Event]' 319 return '[Event]'
320 320
321 def _common_str(self): 321 def _common_str(self):
322 job = self.get_job() 322 job = self.get_job()
323 task = job.get_task() 323 task = job.get_task()
324 return ' for task ' + str(task.get_name()) + ': (TASK, JOB)=' + str((task.get_task_no(), \ 324 return ' for task ' + str(task.get_name()) + ': (TASK, JOB)=' + str((task.get_task_no(), \
325 job.get_job_no())) + ', CPU=' + str(self.get_cpu()) 325 job.get_job_no())) + ', CPU=' + str(self.get_cpu())
326 326
327 def is_erroneous(self): 327 def is_erroneous(self):
328 """An erroneous event is where something with the event is not quite right, 328 """An erroneous event is where something with the event is not quite right,
329 something significantly wrong that we don't have logical information telling 329 something significantly wrong that we don't have logical information telling
330 us how we should render the event.""" 330 us how we should render the event."""
331 return self.erroneous 331 return self.erroneous
332 332
333 def is_selected(self): 333 def is_selected(self):
334 """Returns whether the event has been selected by the user. (needed for rendering)""" 334 """Returns whether the event has been selected by the user. (needed for rendering)"""
335 return self.selected 335 return self.selected
336 336
337 def scan(self, cur_cpu, switches): 337 def scan(self, cur_cpu, switches):
338 """Part of the procedure that walks through all the events and sets 338 """Part of the procedure that walks through all the events and sets
339 some parameters that are unknown at first. For instance, a SwitchAwayEvent 339 some parameters that are unknown at first. For instance, a SwitchAwayEvent
@@ -348,26 +348,26 @@ class Event(DummyEvent):
348 sched.start = time 348 sched.start = time
349 if sched.end is None or time > sched.end: 349 if sched.end is None or time > sched.end:
350 sched.end = time 350 sched.end = time
351 351
352 sched.get_time_slot_array().add_event_to_time_slot(self) 352 sched.get_time_slot_array().add_event_to_time_slot(self)
353 353
354class ErrorEvent(Event): 354class ErrorEvent(Event):
355 pass 355 pass
356 356
357class SuspendEvent(Event): 357class SuspendEvent(Event):
358 def __init__(self, time, cpu): 358 def __init__(self, time, cpu):
359 super(SuspendEvent, self).__init__(time, cpu) 359 super(SuspendEvent, self).__init__(time, cpu)
360 self.layer = Canvas.MIDDLE_LAYER 360 self.layer = Canvas.MIDDLE_LAYER
361 361
362 def __str__(self): 362 def __str__(self):
363 return 'Suspend' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) 363 return 'Suspend' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES)
364 364
365 def scan(self, cur_cpu, switches): 365 def scan(self, cur_cpu, switches):
366 if self.get_cpu() != cur_cpu[0]: 366 if self.get_cpu() != cur_cpu[0]:
367 self.erroneous = True 367 self.erroneous = True
368 #fprint "suspending on a CPU different from the CPU we are on!" 368 #fprint "suspending on a CPU different from the CPU we are on!"
369 super(SuspendEvent, self).scan(cur_cpu, switches) 369 super(SuspendEvent, self).scan(cur_cpu, switches)
370 370
371 def render(self, graph, layer, prev_events, selectable=False): 371 def render(self, graph, layer, prev_events, selectable=False):
372 if layer == self.layer: 372 if layer == self.layer:
373 prev_events[self] = None 373 prev_events[self] = None
@@ -377,22 +377,22 @@ class SuspendEvent(Event):
377 else: 377 else:
378 graph.draw_suspend_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 378 graph.draw_suspend_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
379 self.get_cpu(), self.is_selected()) 379 self.get_cpu(), self.is_selected())
380 380
381 381
382class ResumeEvent(Event): 382class ResumeEvent(Event):
383 def __init__(self, time, cpu): 383 def __init__(self, time, cpu):
384 super(ResumeEvent, self).__init__(time, cpu) 384 super(ResumeEvent, self).__init__(time, cpu)
385 self.layer = Canvas.MIDDLE_LAYER 385 self.layer = Canvas.MIDDLE_LAYER
386 386
387 def __str__(self): 387 def __str__(self):
388 return 'Resume' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) 388 return 'Resume' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES)
389 389
390 def scan(self, cur_cpu, switches): 390 def scan(self, cur_cpu, switches):
391 if cur_cpu[0] != Event.NO_CPU and cur_cpu[0] != self.get_cpu(): 391 if cur_cpu[0] != Event.NO_CPU and cur_cpu[0] != self.get_cpu():
392 self.erroneous = True 392 self.erroneous = True
393 #print "Resuming when currently scheduled on a CPU, but on a different CPU from the current CPU!" 393 #print "Resuming when currently scheduled on a CPU, but on a different CPU from the current CPU!"
394 super(ResumeEvent, self).scan(cur_cpu, switches) 394 super(ResumeEvent, self).scan(cur_cpu, switches)
395 395
396 def render(self, graph, layer, prev_events, selectable=False): 396 def render(self, graph, layer, prev_events, selectable=False):
397 if layer == self.layer: 397 if layer == self.layer:
398 prev_events[self] = None 398 prev_events[self] = None
@@ -402,19 +402,19 @@ class ResumeEvent(Event):
402 else: 402 else:
403 graph.draw_resume_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 403 graph.draw_resume_triangle_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
404 self.get_cpu(), self.is_selected()) 404 self.get_cpu(), self.is_selected())
405 405
406 406
407class CompleteEvent(Event): 407class CompleteEvent(Event):
408 def __init__(self, time, cpu): 408 def __init__(self, time, cpu):
409 super(CompleteEvent, self).__init__(time, cpu) 409 super(CompleteEvent, self).__init__(time, cpu)
410 self.layer = Canvas.TOP_LAYER 410 self.layer = Canvas.TOP_LAYER
411 411
412 def __str__(self): 412 def __str__(self):
413 return 'Complete' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) 413 return 'Complete' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES)
414 414
415 def scan(self, cur_cpu, switches): 415 def scan(self, cur_cpu, switches):
416 super(CompleteEvent, self).scan(cur_cpu, switches) 416 super(CompleteEvent, self).scan(cur_cpu, switches)
417 417
418 def render(self, graph, layer, prev_events, selectable=False): 418 def render(self, graph, layer, prev_events, selectable=False):
419 if layer == Canvas.TOP_LAYER: 419 if layer == Canvas.TOP_LAYER:
420 prev_events[self] = None 420 prev_events[self] = None
@@ -430,7 +430,7 @@ class SwitchToEvent(Event):
430 super(SwitchToEvent, self).__init__(time, cpu) 430 super(SwitchToEvent, self).__init__(time, cpu)
431 self.layer = Canvas.BOTTOM_LAYER 431 self.layer = Canvas.BOTTOM_LAYER
432 self.corresp_end_event = None 432 self.corresp_end_event = None
433 433
434 def __str__(self): 434 def __str__(self):
435 if self.corresp_end_event is None: 435 if self.corresp_end_event is None:
436 return 'Switch To (w/o Switch Away)' + self._common_str() + ', TIME=' \ 436 return 'Switch To (w/o Switch Away)' + self._common_str() + ', TIME=' \
@@ -438,19 +438,19 @@ class SwitchToEvent(Event):
438 return 'Scheduled' + self._common_str() + ', START=' \ 438 return 'Scheduled' + self._common_str() + ', START=' \
439 + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) \ 439 + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) \
440 + ', END=' + util.format_float(self.corresp_end_event.get_time(), Event.NUM_DEC_PLACES) 440 + ', END=' + util.format_float(self.corresp_end_event.get_time(), Event.NUM_DEC_PLACES)
441 441
442 def scan(self, cur_cpu, switches): 442 def scan(self, cur_cpu, switches):
443 old_cur_cpu = cur_cpu[0] 443 old_cur_cpu = cur_cpu[0]
444 cur_cpu[0] = self.get_cpu() 444 cur_cpu[0] = self.get_cpu()
445 switches[SwitchToEvent] = self 445 switches[SwitchToEvent] = self
446 self.corresp_end_event = None 446 self.corresp_end_event = None
447 447
448 if old_cur_cpu != Event.NO_CPU: 448 if old_cur_cpu != Event.NO_CPU:
449 self.erroneous = True 449 self.erroneous = True
450 #print "currently scheduled somewhere, can't switch to a CPU" 450 #print "currently scheduled somewhere, can't switch to a CPU"
451 451
452 super(SwitchToEvent, self).scan(cur_cpu, switches) 452 super(SwitchToEvent, self).scan(cur_cpu, switches)
453 453
454 def render(self, graph, layer, prev_events, selectable=False): 454 def render(self, graph, layer, prev_events, selectable=False):
455 if layer == self.layer: 455 if layer == self.layer:
456 end_time = None 456 end_time = None
@@ -460,7 +460,7 @@ class SwitchToEvent(Event):
460 clip = AlignMode.RIGHT 460 clip = AlignMode.RIGHT
461 else: 461 else:
462 end_time = self.corresp_end_event.get_time() 462 end_time = self.corresp_end_event.get_time()
463 463
464 prev_events[self] = None 464 prev_events[self] = None
465 cpu = self.get_cpu() 465 cpu = self.get_cpu()
466 task_no = self.get_job().get_task().get_task_no() 466 task_no = self.get_job().get_task().get_task_no()
@@ -471,30 +471,30 @@ class SwitchToEvent(Event):
471 graph.draw_bar_at_time(self.get_time(), end_time, 471 graph.draw_bar_at_time(self.get_time(), end_time,
472 task_no, cpu, self.get_job().get_job_no(), 472 task_no, cpu, self.get_job().get_job_no(),
473 clip, self.is_selected()) 473 clip, self.is_selected())
474 474
475class SwitchAwayEvent(Event): 475class SwitchAwayEvent(Event):
476 def __init__(self, time, cpu): 476 def __init__(self, time, cpu):
477 super(SwitchAwayEvent, self).__init__(time, cpu) 477 super(SwitchAwayEvent, self).__init__(time, cpu)
478 self.layer = Canvas.BOTTOM_LAYER 478 self.layer = Canvas.BOTTOM_LAYER
479 self.corresp_start_event = None 479 self.corresp_start_event = None
480 480
481 def __str__(self): 481 def __str__(self):
482 if self.corresp_start_event is None: 482 if self.corresp_start_event is None:
483 return 'Switch Away (w/o Switch To)' + self._common_str() + 'TIME=' \ 483 return 'Switch Away (w/o Switch To)' + self._common_str() + 'TIME=' \
484 + str(self.get_time()) 484 + str(self.get_time())
485 return str(self.corresp_start_event) 485 return str(self.corresp_start_event)
486 486
487 def scan(self, cur_cpu, switches): 487 def scan(self, cur_cpu, switches):
488 old_cur_cpu = cur_cpu[0] 488 old_cur_cpu = cur_cpu[0]
489 489
490 self.corresp_start_event = switches[SwitchToEvent] 490 self.corresp_start_event = switches[SwitchToEvent]
491 491
492 cur_cpu[0] = Event.NO_CPU 492 cur_cpu[0] = Event.NO_CPU
493 switches[SwitchToEvent] = None 493 switches[SwitchToEvent] = None
494 494
495 if self.corresp_start_event is not None: 495 if self.corresp_start_event is not None:
496 self.corresp_start_event.corresp_end_event = self 496 self.corresp_start_event.corresp_end_event = self
497 497
498 if self.get_cpu() != old_cur_cpu: 498 if self.get_cpu() != old_cur_cpu:
499 self.erroneous = True 499 self.erroneous = True
500 #print "switching away from a CPU different from the CPU we are currently on" 500 #print "switching away from a CPU different from the CPU we are currently on"
@@ -504,9 +504,9 @@ class SwitchAwayEvent(Event):
504 elif self.get_time() < self.corresp_start_event.get_time(): 504 elif self.get_time() < self.corresp_start_event.get_time():
505 self.erroneous = True 505 self.erroneous = True
506 #print "switching away from a processor before we switched to it?!" 506 #print "switching away from a processor before we switched to it?!"
507 507
508 super(SwitchAwayEvent, self).scan(cur_cpu, switches) 508 super(SwitchAwayEvent, self).scan(cur_cpu, switches)
509 509
510 def render(self, graph, layer, prev_events, selectable=False): 510 def render(self, graph, layer, prev_events, selectable=False):
511 if self.corresp_start_event is None: 511 if self.corresp_start_event is None:
512 # We never found a corresponding start event. In that case, we can assume it lies 512 # We never found a corresponding start event. In that case, we can assume it lies
@@ -528,18 +528,18 @@ class SwitchAwayEvent(Event):
528 if self.corresp_start_event in prev_events: 528 if self.corresp_start_event in prev_events:
529 return # already rendered the bar 529 return # already rendered the bar
530 self.corresp_start_event.render(graph, layer, prev_events, selectable) 530 self.corresp_start_event.render(graph, layer, prev_events, selectable)
531 531
532class ReleaseEvent(Event): 532class ReleaseEvent(Event):
533 def __init__(self, time, cpu): 533 def __init__(self, time, cpu):
534 super(ReleaseEvent, self).__init__(time, cpu) 534 super(ReleaseEvent, self).__init__(time, cpu)
535 self.layer = Canvas.TOP_LAYER 535 self.layer = Canvas.TOP_LAYER
536 536
537 def __str__(self): 537 def __str__(self):
538 return 'Release' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) 538 return 'Release' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES)
539 539
540 def scan(self, cur_cpu, switches): 540 def scan(self, cur_cpu, switches):
541 super(ReleaseEvent, self).scan(cur_cpu, switches) 541 super(ReleaseEvent, self).scan(cur_cpu, switches)
542 542
543 def render(self, graph, layer, prev_events, selectable=False): 543 def render(self, graph, layer, prev_events, selectable=False):
544 prev_events[self] = None 544 prev_events[self] = None
545 if layer == Canvas.TOP_LAYER: 545 if layer == Canvas.TOP_LAYER:
@@ -549,19 +549,19 @@ class ReleaseEvent(Event):
549 else: 549 else:
550 graph.draw_release_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 550 graph.draw_release_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
551 self.get_job().get_job_no(), self.is_selected()) 551 self.get_job().get_job_no(), self.is_selected())
552 552
553 553
554class DeadlineEvent(Event): 554class DeadlineEvent(Event):
555 def __init__(self, time, cpu): 555 def __init__(self, time, cpu):
556 super(DeadlineEvent, self).__init__(time, cpu) 556 super(DeadlineEvent, self).__init__(time, cpu)
557 self.layer = Canvas.TOP_LAYER 557 self.layer = Canvas.TOP_LAYER
558 558
559 def __str__(self): 559 def __str__(self):
560 return 'Deadline' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) 560 return 'Deadline' + self._common_str() + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES)
561 561
562 def scan(self, cur_cpu, switches): 562 def scan(self, cur_cpu, switches):
563 super(DeadlineEvent, self).scan(cur_cpu, switches) 563 super(DeadlineEvent, self).scan(cur_cpu, switches)
564 564
565 def render(self, graph, layer, prev_events, selectable=False): 565 def render(self, graph, layer, prev_events, selectable=False):
566 prev_events[self] = None 566 prev_events[self] = None
567 if layer == Canvas.TOP_LAYER: 567 if layer == Canvas.TOP_LAYER:
@@ -571,14 +571,14 @@ class DeadlineEvent(Event):
571 else: 571 else:
572 graph.draw_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(), 572 graph.draw_deadline_arrow_at_time(self.get_time(), self.get_job().get_task().get_task_no(),
573 self.get_job().get_job_no(), self.is_selected()) 573 self.get_job().get_job_no(), self.is_selected())
574 574
575 575
576class InversionStartEvent(ErrorEvent): 576class InversionStartEvent(ErrorEvent):
577 def __init__(self, time): 577 def __init__(self, time):
578 super(InversionStartEvent, self).__init__(time, Event.NO_CPU) 578 super(InversionStartEvent, self).__init__(time, Event.NO_CPU)
579 self.layer = Canvas.BOTTOM_LAYER 579 self.layer = Canvas.BOTTOM_LAYER
580 self.corresp_end_event = None 580 self.corresp_end_event = None
581 581
582 def __str__(self): 582 def __str__(self):
583 if self.corresp_end_event is None: 583 if self.corresp_end_event is None:
584 return 'Inversion Start (w/o Inversion End)' + self._common_str() \ 584 return 'Inversion Start (w/o Inversion End)' + self._common_str() \
@@ -586,14 +586,14 @@ class InversionStartEvent(ErrorEvent):
586 return 'Priority Inversion' + self._common_str() + ', START=' \ 586 return 'Priority Inversion' + self._common_str() + ', START=' \
587 + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) \ 587 + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) \
588 + ', END=' + util.format_float(self.corresp_end_event.get_time(), Event.NUM_DEC_PLACES) 588 + ', END=' + util.format_float(self.corresp_end_event.get_time(), Event.NUM_DEC_PLACES)
589 589
590 def scan(self, cur_cpu, switches): 590 def scan(self, cur_cpu, switches):
591 switches[InversionStartEvent] = self 591 switches[InversionStartEvent] = self
592 self.corresp_end_event = None 592 self.corresp_end_event = None
593 593
594 # the corresp_end_event should already be set 594 # the corresp_end_event should already be set
595 super(InversionStartEvent, self).scan(cur_cpu, switches) 595 super(InversionStartEvent, self).scan(cur_cpu, switches)
596 596
597 def render(self, graph, layer, prev_events, selectable=False): 597 def render(self, graph, layer, prev_events, selectable=False):
598 if layer == self.layer: 598 if layer == self.layer:
599 end_time = None 599 end_time = None
@@ -603,7 +603,7 @@ class InversionStartEvent(ErrorEvent):
603 clip = AlignMode.RIGHT 603 clip = AlignMode.RIGHT
604 else: 604 else:
605 end_time = self.corresp_end_event.get_time() 605 end_time = self.corresp_end_event.get_time()
606 606
607 if layer == self.layer: 607 if layer == self.layer:
608 prev_events[self] = None 608 prev_events[self] = None
609 cpu = self.get_cpu() 609 cpu = self.get_cpu()
@@ -615,36 +615,36 @@ class InversionStartEvent(ErrorEvent):
615 graph.draw_mini_bar_at_time(self.get_time(), end_time, 615 graph.draw_mini_bar_at_time(self.get_time(), end_time,
616 task_no, cpu, self.get_job().get_job_no(), 616 task_no, cpu, self.get_job().get_job_no(),
617 clip, self.is_selected()) 617 clip, self.is_selected())
618 618
619 619
620class InversionEndEvent(ErrorEvent): 620class InversionEndEvent(ErrorEvent):
621 def __init__(self, time): 621 def __init__(self, time):
622 super(InversionEndEvent, self).__init__(time, Event.NO_CPU) 622 super(InversionEndEvent, self).__init__(time, Event.NO_CPU)
623 self.layer = Canvas.BOTTOM_LAYER 623 self.layer = Canvas.BOTTOM_LAYER
624 self.corresp_start_event = None 624 self.corresp_start_event = None
625 625
626 def __str__(self): 626 def __str__(self):
627 if self.corresp_start_event is None: 627 if self.corresp_start_event is None:
628 return 'Inversion End (w/o Inversion Start)' + self._common_str() \ 628 return 'Inversion End (w/o Inversion Start)' + self._common_str() \
629 + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES) 629 + ', TIME=' + util.format_float(self.get_time(), Event.NUM_DEC_PLACES)
630 630
631 return str(self.corresp_start_event) 631 return str(self.corresp_start_event)
632 632
633 def scan(self, cur_cpu, switches): 633 def scan(self, cur_cpu, switches):
634 self.corresp_start_event = switches[InversionStartEvent] 634 self.corresp_start_event = switches[InversionStartEvent]
635 635
636 cur_cpu[0] = Event.NO_CPU 636 cur_cpu[0] = Event.NO_CPU
637 switches[InversionStartEvent] = None 637 switches[InversionStartEvent] = None
638 638
639 if self.corresp_start_event is not None: 639 if self.corresp_start_event is not None:
640 self.corresp_start_event.corresp_end_event = self 640 self.corresp_start_event.corresp_end_event = self
641 641
642 if self.corresp_start_event is None: 642 if self.corresp_start_event is None:
643 self.erroneous = True 643 self.erroneous = True
644 print "inversion end was not matched by a corresponding inversion start" 644 print "inversion end was not matched by a corresponding inversion start"
645 645
646 super(InversionEndEvent, self).scan(cur_cpu, switches) 646 super(InversionEndEvent, self).scan(cur_cpu, switches)
647 647
648 def render(self, graph, layer, prev_events, selectable=False): 648 def render(self, graph, layer, prev_events, selectable=False):
649 if self.corresp_start_event is None: 649 if self.corresp_start_event is None:
650 # We never found a corresponding start event. In that case, we can assume it lies 650 # We never found a corresponding start event. In that case, we can assume it lies
@@ -666,27 +666,27 @@ class InversionEndEvent(ErrorEvent):
666 if self.corresp_start_event in prev_events: 666 if self.corresp_start_event in prev_events:
667 return # already rendered the bar 667 return # already rendered the bar
668 self.corresp_start_event.render(graph, layer, prev_events, selectable) 668 self.corresp_start_event.render(graph, layer, prev_events, selectable)
669 669
670class InversionDummy(DummyEvent): 670class InversionDummy(DummyEvent):
671 def __init__(self, time, cpu): 671 def __init__(self, time, cpu):
672 super(InversionDummy, self).__init__(time, Event.NO_CPU) 672 super(InversionDummy, self).__init__(time, Event.NO_CPU)
673 self.layer = Canvas.BOTTOM_LAYER 673 self.layer = Canvas.BOTTOM_LAYER
674 674
675 def render(self, graph, layer, prev_events, selectable=False): 675 def render(self, graph, layer, prev_events, selectable=False):
676 if self.corresp_start_event is None: 676 if self.corresp_start_event is None:
677 if self.corresp_end_event in prev_events: 677 if self.corresp_end_event in prev_events:
678 return # we have already been rendered 678 return # we have already been rendered
679 self.corresp_end_event.render(graph, layer, prev_events, selectable) 679 self.corresp_end_event.render(graph, layer, prev_events, selectable)
680 else: 680 else:
681 if self.corresp_start_event in prev_events: 681 if self.corresp_start_event in prev_events:
682 return # we have already been rendered 682 return # we have already been rendered
683 self.corresp_start_event.render(graph, layer, prev_events, selectable) 683 self.corresp_start_event.render(graph, layer, prev_events, selectable)
684 684
685class IsRunningDummy(DummyEvent): 685class IsRunningDummy(DummyEvent):
686 def __init__(self, time, cpu): 686 def __init__(self, time, cpu):
687 super(IsRunningDummy, self).__init__(time, Event.NO_CPU) 687 super(IsRunningDummy, self).__init__(time, Event.NO_CPU)
688 self.layer = Canvas.BOTTOM_LAYER 688 self.layer = Canvas.BOTTOM_LAYER
689 689
690 def render(self, graph, layer, prev_events, selectable=False): 690 def render(self, graph, layer, prev_events, selectable=False):
691 if self.corresp_start_event is None: 691 if self.corresp_start_event is None:
692 if self.corresp_end_event in prev_events: 692 if self.corresp_end_event in prev_events:
diff --git a/unit_trace/viz/viewer.py b/unit_trace/viz/viewer.py
index 909da76..efc79a1 100644
--- a/unit_trace/viz/viewer.py
+++ b/unit_trace/viz/viewer.py
@@ -13,10 +13,10 @@ import copy
13 13
14class GraphContextMenu(gtk.Menu): 14class GraphContextMenu(gtk.Menu):
15 MAX_STR_LEN = 80 15 MAX_STR_LEN = 80
16 16
17 def __init__(self, selected): 17 def __init__(self, selected):
18 super(GraphContextMenu, self).__init__() 18 super(GraphContextMenu, self).__init__()
19 19
20 for event in selected: 20 for event in selected:
21 string = str(event) 21 string = str(event)
22 if len(string) > GraphContextMenu.MAX_STR_LEN - 3: 22 if len(string) > GraphContextMenu.MAX_STR_LEN - 3:
@@ -24,100 +24,100 @@ class GraphContextMenu(gtk.Menu):
24 item = gtk.MenuItem(string) 24 item = gtk.MenuItem(string)
25 self.append(item) 25 self.append(item)
26 item.show() 26 item.show()
27 27
28class GraphArea(gtk.DrawingArea): 28class GraphArea(gtk.DrawingArea):
29 HORIZ_PAGE_SCROLL_FACTOR = 10.8 29 HORIZ_PAGE_SCROLL_FACTOR = 10.8
30 HORIZ_STEP_SCROLL_FACTOR = 0.8 30 HORIZ_STEP_SCROLL_FACTOR = 0.8
31 VERT_PAGE_SCROLL_FACTOR = 3.0 31 VERT_PAGE_SCROLL_FACTOR = 3.0
32 VERT_STEP_SCROLL_FACTOR = 0.5 32 VERT_STEP_SCROLL_FACTOR = 0.5
33 33
34 REFRESH_INFLATION_FACTOR = 20.0 34 REFRESH_INFLATION_FACTOR = 20.0
35 35
36 def __init__(self, renderer): 36 def __init__(self, renderer):
37 super(GraphArea, self).__init__() 37 super(GraphArea, self).__init__()
38 38
39 self.renderer = renderer 39 self.renderer = renderer
40 40
41 self.cur_x = 0 41 self.cur_x = 0
42 self.cur_y = 0 42 self.cur_y = 0
43 self.width = 0 43 self.width = 0
44 self.height = 0 44 self.height = 0
45 45
46 self.set_set_scroll_adjustments_signal('set-scroll-adjustments') 46 self.set_set_scroll_adjustments_signal('set-scroll-adjustments')
47 47
48 self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | 48 self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK |
49 gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.EXPOSURE_MASK) 49 gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.EXPOSURE_MASK)
50 50
51 self.band_rect = None 51 self.band_rect = None
52 self.ctrl_clicked = False 52 self.ctrl_clicked = False
53 self.dirtied_regions = [] 53 self.dirtied_regions = []
54 54
55 self.connect('expose-event', self.expose) 55 self.connect('expose-event', self.expose)
56 self.connect('size-allocate', self.size_allocate) 56 self.connect('size-allocate', self.size_allocate)
57 self.connect('set-scroll-adjustments', self.set_scroll_adjustments) 57 self.connect('set-scroll-adjustments', self.set_scroll_adjustments)
58 self.connect('button-press-event', self.button_press) 58 self.connect('button-press-event', self.button_press)
59 self.connect('button-release-event', self.button_release) 59 self.connect('button-release-event', self.button_release)
60 self.connect('motion-notify-event', self.motion_notify) 60 self.connect('motion-notify-event', self.motion_notify)
61 61
62 def expose(self, widget, expose_event, data=None): 62 def expose(self, widget, expose_event, data=None):
63 ctx = widget.window.cairo_create() 63 ctx = widget.window.cairo_create()
64 graph = self.renderer.get_graph() 64 graph = self.renderer.get_graph()
65 graph.update_view(self.cur_x, self.cur_y, self.width, self.height, ctx) 65 graph.update_view(self.cur_x, self.cur_y, self.width, self.height, ctx)
66 66
67 # We ourselves didn't update dirtied_regions, so this means that X or the 67 # We ourselves didn't update dirtied_regions, so this means that X or the
68 # window manager must have caused the expose event. So just update the 68 # window manager must have caused the expose event. So just update the
69 # expose_event's bounding area. 69 # expose_event's bounding area.
70 if not self.dirtied_regions or expose_event.send_event: 70 if not self.dirtied_regions or expose_event.send_event:
71 self.dirtied_regions = [(expose_event.area.x, expose_event.area.y, 71 self.dirtied_regions = [(expose_event.area.x, expose_event.area.y,
72 expose_event.area.width, expose_event.area.height)] 72 expose_event.area.width, expose_event.area.height)]
73 73
74 graph.render_surface(self.renderer.get_schedule(), self.dirtied_regions) 74 graph.render_surface(self.renderer.get_schedule(), self.dirtied_regions)
75 75
76 # render dragging band rectangle, if there is one 76 # render dragging band rectangle, if there is one
77 if self.band_rect is not None: 77 if self.band_rect is not None:
78 x, y, width, height = self.band_rect 78 x, y, width, height = self.band_rect
79 thickness = GraphFormat.BAND_THICKNESS 79 thickness = GraphFormat.BAND_THICKNESS
80 color = GraphFormat.BAND_COLOR 80 color = GraphFormat.BAND_COLOR
81 81
82 ctx.rectangle(x, y, width, height) 82 ctx.rectangle(x, y, width, height)
83 ctx.set_line_width(thickness) 83 ctx.set_line_width(thickness)
84 ctx.set_source_rgb(color[0], color[1], color[2]) 84 ctx.set_source_rgb(color[0], color[1], color[2])
85 ctx.stroke() 85 ctx.stroke()
86 86
87 self.dirtied_regions = [] 87 self.dirtied_regions = []
88 88
89 def get_renderer(self): 89 def get_renderer(self):
90 return self.renderer 90 return self.renderer
91 91
92 def get_graph(self): 92 def get_graph(self):
93 return self.renderer.get_graph() 93 return self.renderer.get_graph()
94 94
95 def set_scroll_adjustments(self, widget, horizontal, vertical, data=None): 95 def set_scroll_adjustments(self, widget, horizontal, vertical, data=None):
96 graph = self.renderer.get_graph() 96 graph = self.renderer.get_graph()
97 width = graph.get_width() 97 width = graph.get_width()
98 height = graph.get_height() 98 height = graph.get_height()
99 99
100 self.horizontal = horizontal 100 self.horizontal = horizontal
101 self.vertical = vertical 101 self.vertical = vertical
102 self.config_scrollbars(self.cur_x, self.cur_y) 102 self.config_scrollbars(self.cur_x, self.cur_y)
103 103
104 if self.horizontal is not None: 104 if self.horizontal is not None:
105 self.horizontal.connect('value-changed', self.horizontal_value_changed) 105 self.horizontal.connect('value-changed', self.horizontal_value_changed)
106 if self.vertical is not None: 106 if self.vertical is not None:
107 self.vertical.connect('value-changed', self.vertical_value_changed) 107 self.vertical.connect('value-changed', self.vertical_value_changed)
108 108
109 def horizontal_value_changed(self, adjustment): 109 def horizontal_value_changed(self, adjustment):
110 self.cur_x = min(adjustment.value, self.renderer.get_graph().get_width()) 110 self.cur_x = min(adjustment.value, self.renderer.get_graph().get_width())
111 self.cur_x = max(adjustment.value, 0.0) 111 self.cur_x = max(adjustment.value, 0.0)
112 112
113 self._dirty(0, 0, self.width, self.height) 113 self._dirty(0, 0, self.width, self.height)
114 114
115 def vertical_value_changed(self, adjustment): 115 def vertical_value_changed(self, adjustment):
116 self.cur_y = min(adjustment.value, self.renderer.get_graph().get_height()) 116 self.cur_y = min(adjustment.value, self.renderer.get_graph().get_height())
117 self.cur_y = max(adjustment.value, 0.0) 117 self.cur_y = max(adjustment.value, 0.0)
118 118
119 self._dirty(0, 0, self.width, self.height) 119 self._dirty(0, 0, self.width, self.height)
120 120
121 def size_allocate(self, widget, allocation): 121 def size_allocate(self, widget, allocation):
122 self.width = allocation.width 122 self.width = allocation.width
123 self.height = allocation.height 123 self.height = allocation.height
@@ -127,21 +127,21 @@ class GraphArea(gtk.DrawingArea):
127 graph = self.renderer.get_graph() 127 graph = self.renderer.get_graph()
128 width = graph.get_width() 128 width = graph.get_width()
129 height = graph.get_height() 129 height = graph.get_height()
130 130
131 if self.horizontal is not None: 131 if self.horizontal is not None:
132 self.horizontal.set_all(hvalue, 0.0, width, graph.get_attrs().maj_sep * GraphArea.HORIZ_STEP_SCROLL_FACTOR, 132 self.horizontal.set_all(hvalue, 0.0, width, graph.get_attrs().maj_sep * GraphArea.HORIZ_STEP_SCROLL_FACTOR,
133 graph.get_attrs().maj_sep * GraphArea.HORIZ_PAGE_SCROLL_FACTOR, self.width) 133 graph.get_attrs().maj_sep * GraphArea.HORIZ_PAGE_SCROLL_FACTOR, self.width)
134 if self.vertical is not None: 134 if self.vertical is not None:
135 self.vertical.set_all(vvalue, 0.0, height, graph.get_attrs().y_item_size * GraphArea.VERT_STEP_SCROLL_FACTOR, 135 self.vertical.set_all(vvalue, 0.0, height, graph.get_attrs().y_item_size * GraphArea.VERT_STEP_SCROLL_FACTOR,
136 graph.get_attrs().y_item_size * GraphArea.VERT_PAGE_SCROLL_FACTOR, self.height) 136 graph.get_attrs().y_item_size * GraphArea.VERT_PAGE_SCROLL_FACTOR, self.height)
137 137
138 def _find_max_layer(self, regions): 138 def _find_max_layer(self, regions):
139 max_layer = Canvas.BOTTOM_LAYER 139 max_layer = Canvas.BOTTOM_LAYER
140 for event in regions: 140 for event in regions:
141 if event.get_layer() > max_layer: 141 if event.get_layer() > max_layer:
142 max_layer = event.get_layer() 142 max_layer = event.get_layer()
143 return max_layer 143 return max_layer
144 144
145 def _update_event_changes(self, list1, list2): 145 def _update_event_changes(self, list1, list2):
146 # if an event changed selected status, update the bounding area 146 # if an event changed selected status, update the bounding area
147 for event in list1: 147 for event in list1:
@@ -152,12 +152,12 @@ class GraphArea(gtk.DrawingArea):
152 if event not in list1: 152 if event not in list1:
153 x, y, width, height = list2[event].get_dimensions() 153 x, y, width, height = list2[event].get_dimensions()
154 self._dirty_inflate(x - self.cur_x, y - self.cur_y, width, height, GraphFormat.BORDER_THICKNESS) 154 self._dirty_inflate(x - self.cur_x, y - self.cur_y, width, height, GraphFormat.BORDER_THICKNESS)
155 155
156 def motion_notify(self, widget, motion_event, data=None): 156 def motion_notify(self, widget, motion_event, data=None):
157 msg = None 157 msg = None
158 158
159 graph = self.renderer.get_graph() 159 graph = self.renderer.get_graph()
160 160
161 graph.render_surface(self.renderer.get_schedule(), [(motion_event.x, motion_event.y, 161 graph.render_surface(self.renderer.get_schedule(), [(motion_event.x, motion_event.y,
162 0, 0)], True) 162 0, 0)], True)
163 just_selected = graph.get_selected_regions(motion_event.x, motion_event.y, 0, 0) 163 just_selected = graph.get_selected_regions(motion_event.x, motion_event.y, 0, 0)
@@ -166,62 +166,62 @@ class GraphArea(gtk.DrawingArea):
166 the_event = None 166 the_event = None
167 else: 167 else:
168 max_layer = self._find_max_layer(just_selected) 168 max_layer = self._find_max_layer(just_selected)
169 169
170 for event in just_selected: 170 for event in just_selected:
171 if event.get_layer() == max_layer: 171 if event.get_layer() == max_layer:
172 the_event = event 172 the_event = event
173 break 173 break
174 174
175 msg = str(the_event) 175 msg = str(the_event)
176 176
177 self.emit('update-event-description', the_event, msg) 177 self.emit('update-event-description', the_event, msg)
178 178
179 if self.band_rect is not None: 179 if self.band_rect is not None:
180 selected = {} 180 selected = {}
181 was_selected = self.renderer.get_schedule().get_selected() 181 was_selected = self.renderer.get_schedule().get_selected()
182 if self.ctrl_clicked: 182 if self.ctrl_clicked:
183 selected = copy.copy(was_selected) 183 selected = copy.copy(was_selected)
184 184
185 # dragging a rectangle 185 # dragging a rectangle
186 x = self.band_rect[0] 186 x = self.band_rect[0]
187 y = self.band_rect[1] 187 y = self.band_rect[1]
188 width = motion_event.x - self.band_rect[0] 188 width = motion_event.x - self.band_rect[0]
189 height = motion_event.y - self.band_rect[1] 189 height = motion_event.y - self.band_rect[1]
190 190
191 x_p, y_p, width_p, height_p = self._positivify(x, y, width, height) 191 x_p, y_p, width_p, height_p = self._positivify(x, y, width, height)
192 graph.render_surface(self.renderer.get_schedule(), [(x_p, y_p, width_p, height_p)], True) 192 graph.render_surface(self.renderer.get_schedule(), [(x_p, y_p, width_p, height_p)], True)
193 selected.update(graph.get_selected_regions(x_p, y_p, width_p, height_p)) 193 selected.update(graph.get_selected_regions(x_p, y_p, width_p, height_p))
194 self.renderer.get_schedule().set_selected(selected) 194 self.renderer.get_schedule().set_selected(selected)
195 195
196 old_x, old_y, old_width, old_height = self.band_rect 196 old_x, old_y, old_width, old_height = self.band_rect
197 self.band_rect = (x, y, width, height) 197 self.band_rect = (x, y, width, height)
198 198
199 self._dirty_rect_border(old_x, old_y, old_width, old_height, GraphFormat.BAND_THICKNESS) 199 self._dirty_rect_border(old_x, old_y, old_width, old_height, GraphFormat.BAND_THICKNESS)
200 self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS) 200 self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS)
201 201
202 self._update_event_changes(was_selected, selected) 202 self._update_event_changes(was_selected, selected)
203 203
204 def button_press(self, widget, button_event, data=None): 204 def button_press(self, widget, button_event, data=None):
205 graph = self.renderer.get_graph() 205 graph = self.renderer.get_graph()
206 206
207 self.ctrl_clicked = button_event.state & gtk.gdk.CONTROL_MASK 207 self.ctrl_clicked = button_event.state & gtk.gdk.CONTROL_MASK
208 208
209 if button_event.button == 1: 209 if button_event.button == 1:
210 self.left_button_start_coor = (button_event.x, button_event.y) 210 self.left_button_start_coor = (button_event.x, button_event.y)
211 graph.render_surface(self.renderer.get_schedule(), \ 211 graph.render_surface(self.renderer.get_schedule(), \
212 [(button_event.x, button_event.y, 0, 0)], True) 212 [(button_event.x, button_event.y, 0, 0)], True)
213 213
214 just_selected = graph.get_selected_regions(button_event.x, button_event.y, 0, 0) 214 just_selected = graph.get_selected_regions(button_event.x, button_event.y, 0, 0)
215 215
216 max_layer = self._find_max_layer(just_selected) 216 max_layer = self._find_max_layer(just_selected)
217 217
218 new_now_selected = None 218 new_now_selected = None
219 was_selected = self.renderer.get_schedule().get_selected() 219 was_selected = self.renderer.get_schedule().get_selected()
220 if self.ctrl_clicked: 220 if self.ctrl_clicked:
221 new_now_selected = copy.copy(was_selected) 221 new_now_selected = copy.copy(was_selected)
222 else: 222 else:
223 new_now_selected = {} 223 new_now_selected = {}
224 224
225 # only select those events which were in the top layer (it's 225 # only select those events which were in the top layer (it's
226 # not intuitive to click something and then have something 226 # not intuitive to click something and then have something
227 # below it get selected). Also, clicking something that 227 # below it get selected). Also, clicking something that
@@ -237,43 +237,43 @@ class GraphArea(gtk.DrawingArea):
237 elif event in new_now_selected: 237 elif event in new_now_selected:
238 del new_now_selected[event] 238 del new_now_selected[event]
239 break # only pick one event when just clicking 239 break # only pick one event when just clicking
240 240
241 self.renderer.get_schedule().set_selected(new_now_selected) 241 self.renderer.get_schedule().set_selected(new_now_selected)
242 #self.last_selected = new_now_selected 242 #self.last_selected = new_now_selected
243 243
244 self._update_event_changes(new_now_selected, was_selected) 244 self._update_event_changes(new_now_selected, was_selected)
245 245
246 if self.band_rect is None: 246 if self.band_rect is None:
247 self.band_rect = (button_event.x, button_event.y, 0, 0) 247 self.band_rect = (button_event.x, button_event.y, 0, 0)
248 248
249 elif button_event.button == 3: 249 elif button_event.button == 3:
250 self._release_band() 250 self._release_band()
251 self.emit('request-context-menu', button_event, self.renderer.get_schedule().get_selected()) 251 self.emit('request-context-menu', button_event, self.renderer.get_schedule().get_selected())
252 252
253 def button_release(self, widget, button_event, data=None): 253 def button_release(self, widget, button_event, data=None):
254 self.ctrl_clicked = False 254 self.ctrl_clicked = False
255 #self.last_selected = copy.copy(self.renderer.get_schedule().get_selected()) 255 #self.last_selected = copy.copy(self.renderer.get_schedule().get_selected())
256 256
257 if button_event.button == 1: 257 if button_event.button == 1:
258 self._release_band() 258 self._release_band()
259 259
260 def _release_band(self): 260 def _release_band(self):
261 if self.band_rect is not None: 261 if self.band_rect is not None:
262 x, y, width, height = self.band_rect 262 x, y, width, height = self.band_rect
263 self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS) 263 self._dirty_rect_border(x, y, width, height, GraphFormat.BAND_THICKNESS)
264 self.band_rect = None 264 self.band_rect = None
265 265
266 def _dirty(self, x, y, width, height): 266 def _dirty(self, x, y, width, height):
267 x = max(int(math.floor(x)), 0) 267 x = max(int(math.floor(x)), 0)
268 y = max(int(math.floor(y)), 0) 268 y = max(int(math.floor(y)), 0)
269 width = min(int(math.ceil(width)), self.width) 269 width = min(int(math.ceil(width)), self.width)
270 height = min(int(math.ceil(height)), self.height) 270 height = min(int(math.ceil(height)), self.height)
271 271
272 self.dirtied_regions.append((x, y, width, height)) 272 self.dirtied_regions.append((x, y, width, height))
273 273
274 rect = gtk.gdk.Rectangle(x, y, width, height) 274 rect = gtk.gdk.Rectangle(x, y, width, height)
275 self.window.invalidate_rect(rect, True) 275 self.window.invalidate_rect(rect, True)
276 276
277 def _dirty_inflate(self, x, y, width, height, thickness): 277 def _dirty_inflate(self, x, y, width, height, thickness):
278 t = thickness * GraphArea.REFRESH_INFLATION_FACTOR 278 t = thickness * GraphArea.REFRESH_INFLATION_FACTOR
279 x -= t / 2.0 279 x -= t / 2.0
@@ -281,17 +281,17 @@ class GraphArea(gtk.DrawingArea):
281 width += t 281 width += t
282 height += t 282 height += t
283 self._dirty(x, y, width, height) 283 self._dirty(x, y, width, height)
284 284
285 def _dirty_rect_border(self, x, y, width, height, thickness): 285 def _dirty_rect_border(self, x, y, width, height, thickness):
286 # support rectangles with negative width and height (i.e. -width = width, but going leftwards 286 # support rectangles with negative width and height (i.e. -width = width, but going leftwards
287 # instead of rightwards) 287 # instead of rightwards)
288 x, y, width, height = self._positivify(x, y, width, height) 288 x, y, width, height = self._positivify(x, y, width, height)
289 289
290 self._dirty_inflate(x, y, width, 0, thickness) 290 self._dirty_inflate(x, y, width, 0, thickness)
291 self._dirty_inflate(x, y, 0, height, thickness) 291 self._dirty_inflate(x, y, 0, height, thickness)
292 self._dirty_inflate(x, y + height, width, 0, thickness) 292 self._dirty_inflate(x, y + height, width, 0, thickness)
293 self._dirty_inflate(x + width, y, 0, height, thickness) 293 self._dirty_inflate(x + width, y, 0, height, thickness)
294 294
295 def _positivify(self, x, y, width, height): 295 def _positivify(self, x, y, width, height):
296 if width < 0: 296 if width < 0:
297 x += width 297 x += width
@@ -299,28 +299,28 @@ class GraphArea(gtk.DrawingArea):
299 if height < 0: 299 if height < 0:
300 y += height 300 y += height
301 height = -height 301 height = -height
302 302
303 return x, y, width, height 303 return x, y, width, height
304 304
305class GraphWindow(gtk.ScrolledWindow): 305class GraphWindow(gtk.ScrolledWindow):
306 def __init__(self, renderer): 306 def __init__(self, renderer):
307 super(GraphWindow, self).__init__(None, None) 307 super(GraphWindow, self).__init__(None, None)
308 308
309 self.add_events(gtk.gdk.KEY_PRESS_MASK) 309 self.add_events(gtk.gdk.KEY_PRESS_MASK)
310 310
311 self.ctr = 0 311 self.ctr = 0
312 self.connect('key-press-event', self.key_press) 312 self.connect('key-press-event', self.key_press)
313 313
314 self.garea = GraphArea(renderer) 314 self.garea = GraphArea(renderer)
315 self.add(self.garea) 315 self.add(self.garea)
316 self.garea.show() 316 self.garea.show()
317 317
318 def key_press(self, widget, key_event): 318 def key_press(self, widget, key_event):
319 hadj = self.get_hadjustment() 319 hadj = self.get_hadjustment()
320 vadj = self.get_vadjustment() 320 vadj = self.get_vadjustment()
321 if hadj is None or vadj is None: 321 if hadj is None or vadj is None:
322 return 322 return
323 323
324 hupper = hadj.get_upper() 324 hupper = hadj.get_upper()
325 hlower = hadj.get_lower() 325 hlower = hadj.get_lower()
326 hpincr = hadj.get_page_increment() 326 hpincr = hadj.get_page_increment()
@@ -333,9 +333,9 @@ class GraphWindow(gtk.ScrolledWindow):
333 vpincr = vadj.get_page_increment() 333 vpincr = vadj.get_page_increment()
334 vsincr = vadj.get_step_increment() 334 vsincr = vadj.get_step_increment()
335 vpsize = vadj.get_page_size() 335 vpsize = vadj.get_page_size()
336 336
337 ctrl_clicked = key_event.state & gtk.gdk.CONTROL_MASK 337 ctrl_clicked = key_event.state & gtk.gdk.CONTROL_MASK
338 338
339 adj_tuple = {'up' : (vadj, -vsincr, 0, vval, max), 339 adj_tuple = {'up' : (vadj, -vsincr, 0, vval, max),
340 'ctrl-up' : (vadj, -vpincr, 0, vval, max), 340 'ctrl-up' : (vadj, -vpincr, 0, vval, max),
341 'down' : (vadj, vsincr, vupper - vpsize, vval, min), 341 'down' : (vadj, vsincr, vupper - vpsize, vval, min),
@@ -344,78 +344,78 @@ class GraphWindow(gtk.ScrolledWindow):
344 'ctrl-left' : (hadj, -hpincr, 0, hval, max), 344 'ctrl-left' : (hadj, -hpincr, 0, hval, max),
345 'right' : (hadj, hsincr, hupper - hpsize, hval, min), 345 'right' : (hadj, hsincr, hupper - hpsize, hval, min),
346 'ctrl-right' : (hadj, hpincr, hupper - hpsize, hval, min)} 346 'ctrl-right' : (hadj, hpincr, hupper - hpsize, hval, min)}
347 347
348 keystr = None 348 keystr = None
349 keymap = {gtk.keysyms.Up : 'up', gtk.keysyms.Down : 'down', 349 keymap = {gtk.keysyms.Up : 'up', gtk.keysyms.Down : 'down',
350 gtk.keysyms.Left : 'left', gtk.keysyms.Right : 'right'} 350 gtk.keysyms.Left : 'left', gtk.keysyms.Right : 'right'}
351 if key_event.keyval in keymap: 351 if key_event.keyval in keymap:
352 keystr = keymap[key_event.keyval] 352 keystr = keymap[key_event.keyval]
353 353
354 if ctrl_clicked: 354 if ctrl_clicked:
355 keystr = 'ctrl-' + keystr 355 keystr = 'ctrl-' + keystr
356 356
357 if keystr is not None: 357 if keystr is not None:
358 adj, inc, lim, val, extr = adj_tuple[keystr] 358 adj, inc, lim, val, extr = adj_tuple[keystr]
359 adj.set_value(extr(val + inc, lim)) 359 adj.set_value(extr(val + inc, lim))
360 360
361 return True 361 return True
362 362
363 def get_graph_area(self): 363 def get_graph_area(self):
364 return self.garea 364 return self.garea
365 365
366class MainWindow(gtk.Window): 366class MainWindow(gtk.Window):
367 WINDOW_WIDTH_REQ = 500 367 WINDOW_WIDTH_REQ = 500
368 WINDOW_HEIGHT_REQ = 300 368 WINDOW_HEIGHT_REQ = 300
369 369
370 def __init__(self): 370 def __init__(self):
371 super(MainWindow, self).__init__(gtk.WINDOW_TOPLEVEL) 371 super(MainWindow, self).__init__(gtk.WINDOW_TOPLEVEL)
372 372
373 self.connect('delete_event', self.delete_event) 373 self.connect('delete_event', self.delete_event)
374 self.connect('destroy', self.die) 374 self.connect('destroy', self.die)
375 375
376 self.file_menu = gtk.Menu() 376 self.file_menu = gtk.Menu()
377 self.quit_item = gtk.MenuItem('_Quit', True) 377 self.quit_item = gtk.MenuItem('_Quit', True)
378 self.quit_item.connect('activate', self.quit_item_activate) 378 self.quit_item.connect('activate', self.quit_item_activate)
379 self.quit_item.show() 379 self.quit_item.show()
380 self.file_menu.append(self.quit_item) 380 self.file_menu.append(self.quit_item)
381 381
382 self.file_item = gtk.MenuItem('_File', True) 382 self.file_item = gtk.MenuItem('_File', True)
383 self.file_item.set_submenu(self.file_menu) 383 self.file_item.set_submenu(self.file_menu)
384 self.file_item.show() 384 self.file_item.show()
385 385
386 self.menu_bar = gtk.MenuBar() 386 self.menu_bar = gtk.MenuBar()
387 self.menu_bar.append(self.file_item) 387 self.menu_bar.append(self.file_item)
388 388
389 self.menu_bar.show() 389 self.menu_bar.show()
390 390
391 self.vbox = gtk.VBox(False, 0) 391 self.vbox = gtk.VBox(False, 0)
392 392
393 self.notebook = gtk.Notebook() 393 self.notebook = gtk.Notebook()
394 394
395 self.notebook.last_page = -1 395 self.notebook.last_page = -1
396 self.notebook.connect('switch-page', self.switch_page) 396 self.notebook.connect('switch-page', self.switch_page)
397 397
398 self.notebook.show() 398 self.notebook.show()
399 399
400 self.desc_label = gtk.Label('') 400 self.desc_label = gtk.Label('')
401 self.desc_label.set_justify(gtk.JUSTIFY_LEFT) 401 self.desc_label.set_justify(gtk.JUSTIFY_LEFT)
402 self.desc_label.show() 402 self.desc_label.show()
403 403
404 self.vbox.pack_start(self.menu_bar, False, False, 0) 404 self.vbox.pack_start(self.menu_bar, False, False, 0)
405 self.vbox.pack_start(self.notebook, True, True, 0) 405 self.vbox.pack_start(self.notebook, True, True, 0)
406 self.vbox.pack_start(self.desc_label, False, False, 0) 406 self.vbox.pack_start(self.desc_label, False, False, 0)
407 self.vbox.show() 407 self.vbox.show()
408 408
409 self.add(self.vbox) 409 self.add(self.vbox)
410 410
411 self.set_size_request(MainWindow.WINDOW_WIDTH_REQ, MainWindow.WINDOW_HEIGHT_REQ) 411 self.set_size_request(MainWindow.WINDOW_WIDTH_REQ, MainWindow.WINDOW_HEIGHT_REQ)
412 412
413 self.show() 413 self.show()
414 414
415 def connect_widgets(self, garea): 415 def connect_widgets(self, garea):
416 garea.connect('update-event-description', self.update_event_description) 416 garea.connect('update-event-description', self.update_event_description)
417 garea.connect('request-context-menu', self.request_context_menu) 417 garea.connect('request-context-menu', self.request_context_menu)
418 418
419 def set_renderers(self, renderers): 419 def set_renderers(self, renderers):
420 for i in range(0, self.notebook.get_n_pages()): 420 for i in range(0, self.notebook.get_n_pages()):
421 self.notebook.remove_page(0) 421 self.notebook.remove_page(0)
@@ -424,7 +424,7 @@ class MainWindow(gtk.Window):
424 self.connect_widgets(gwindow.get_graph_area()) 424 self.connect_widgets(gwindow.get_graph_area())
425 gwindow.show() 425 gwindow.show()
426 self.notebook.append_page(gwindow, gtk.Label(title)) 426 self.notebook.append_page(gwindow, gtk.Label(title))
427 427
428 def switch_page(self, widget, page, page_num): 428 def switch_page(self, widget, page, page_num):
429 if self.notebook.get_nth_page(self.notebook.last_page) is not None: 429 if self.notebook.get_nth_page(self.notebook.last_page) is not None:
430 old_value = self.notebook.get_nth_page(self.notebook.last_page).get_hadjustment().get_value() 430 old_value = self.notebook.get_nth_page(self.notebook.last_page).get_hadjustment().get_value()
@@ -432,27 +432,27 @@ class MainWindow(gtk.Window):
432 new_ofs = self.notebook.get_nth_page(page_num).get_graph_area().get_graph().get_origin()[0] 432 new_ofs = self.notebook.get_nth_page(page_num).get_graph_area().get_graph().get_origin()[0]
433 new_value = old_value - old_ofs + new_ofs 433 new_value = old_value - old_ofs + new_ofs
434 self.notebook.get_nth_page(page_num).get_hadjustment().set_value(new_value) 434 self.notebook.get_nth_page(page_num).get_hadjustment().set_value(new_value)
435 435
436 self.notebook.last_page = page_num 436 self.notebook.last_page = page_num
437 437
438 def update_event_description(self, widget, event, msg): 438 def update_event_description(self, widget, event, msg):
439 self.desc_label.set_text(msg) 439 self.desc_label.set_text(msg)
440 440
441 def request_context_menu(self, widget, gdk_event, selected): 441 def request_context_menu(self, widget, gdk_event, selected):
442 button = 0 442 button = 0
443 if hasattr(gdk_event, 'button'): 443 if hasattr(gdk_event, 'button'):
444 button = gdk_event.button 444 button = gdk_event.button
445 time = gdk_event.time 445 time = gdk_event.time
446 446
447 menu = GraphContextMenu(selected) 447 menu = GraphContextMenu(selected)
448 menu.popup(None, None, None, button, time) 448 menu.popup(None, None, None, button, time)
449 449
450 def quit_item_activate(self, widget): 450 def quit_item_activate(self, widget):
451 self.destroy() 451 self.destroy()
452 452
453 def delete_event(self, widget, event, data=None): 453 def delete_event(self, widget, event, data=None):
454 return False 454 return False
455 455
456 def die(self, widget, data=None): 456 def die(self, widget, data=None):
457 gtk.main_quit() 457 gtk.main_quit()
458 458
diff --git a/unit_trace/viz/visualizer.py b/unit_trace/viz/visualizer.py
index d739736..63594bd 100755
--- a/unit_trace/viz/visualizer.py
+++ b/unit_trace/viz/visualizer.py
@@ -13,13 +13,13 @@ TIME_PER_MAJ = 10000000
13def visualizer(stream): 13def visualizer(stream):
14 sched = convert.convert_trace_to_schedule(stream) 14 sched = convert.convert_trace_to_schedule(stream)
15 sched.scan(TIME_PER_MAJ) 15 sched.scan(TIME_PER_MAJ)
16 16
17 task_renderer = renderer.Renderer(sched) 17 task_renderer = renderer.Renderer(sched)
18 task_renderer.prepare_task_graph(attrs=format.GraphFormat(time_per_maj=TIME_PER_MAJ)) 18 task_renderer.prepare_task_graph(attrs=format.GraphFormat(time_per_maj=TIME_PER_MAJ))
19 cpu_renderer = renderer.Renderer(sched) 19 cpu_renderer = renderer.Renderer(sched)
20 cpu_renderer.prepare_cpu_graph(attrs=format.GraphFormat(time_per_maj=TIME_PER_MAJ)) 20 cpu_renderer.prepare_cpu_graph(attrs=format.GraphFormat(time_per_maj=TIME_PER_MAJ))
21 21
22 window = viewer.MainWindow() 22 window = viewer.MainWindow()
23 window.set_renderers({'Tasks' : task_renderer, 'CPUs' : cpu_renderer}) 23 window.set_renderers({'Tasks' : task_renderer, 'CPUs' : cpu_renderer})
24 24
25 gtk.main() 25 gtk.main()