00001
00002
00003 import graph.style as gs
00004 import graph
00005 import graph.layout as gl
00006
00007 import tool_utils as tu
00008 import graph_model as gm
00009
00010 import numpy as np
00011 import time
00012 import copy
00013
00014 def copy_style(astyle, bstyle):
00015 bstyle.background = astyle.background
00016 bstyle.fill = astyle.fill
00017 bstyle.stroke = astyle.stroke
00018 bstyle.strokewidth = astyle.strokewidth
00019 bstyle.text = astyle.text
00020 bstyle.font = astyle.font
00021 bstyle.fontsize = astyle.fontsize
00022 bstyle.textwidth = astyle.textwidth
00023 bstyle.align = astyle.align
00024 bstyle.depth = astyle.depth
00025
00026 class GraphView:
00027
00028 def __init__(self, context, graph_model):
00029 self.graph_model = graph_model
00030 g = self.graph_model.gve
00031 self.gve = g
00032 self.context = context
00033
00034 node_outlines = self.context.color(0.4, 0.4, 0.4, 1.)
00035 text_color = self.context.color(0.3, 0.3, 0.3, 1.)
00036 node_font_size = 14
00037
00038
00039 g.styles.default.depth = True
00040 g.styles.default.background = self.context.color(1., 1., 1., 1.)
00041 g.styles.default.stroke = node_outlines
00042 g.styles.default.text = text_color
00043 g.styles.default.fontsize = node_font_size
00044 g.styles.root.text = self.context.color(255/255., 153/255., 51/255., 1.)
00045
00046 g.styles.important.fontsize = node_font_size
00047 g.styles.important.text = text_color
00048 g.styles.important.stroke = node_outlines
00049
00050 g.styles.marked.fontsize = node_font_size
00051 g.styles.marked.text = text_color
00052 g.styles.marked.stroke = node_outlines
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 self.refresh = self.gve.layout.refresh
00064
00065 old_outcome_style = g.styles.create('old_outcome')
00066 active_node_style = g.styles.create('active_node')
00067 selected_style = g.styles.create('selected')
00068 normal_style = g.styles.create('normal')
00069 normal_edge_style = g.styles.create('normal_edge')
00070 selected_edge_style = g.styles.create('selected_edge')
00071 graph_circle = g.styles.create('graph_circle')
00072 container = g.styles.create('container')
00073 container_selected = g.styles.create('container_selected')
00074
00075 copy_style(g.styles.important, old_outcome_style)
00076 copy_style(g.styles.important, active_node_style)
00077 copy_style(g.styles.important, selected_style)
00078 copy_style(g.styles.default, normal_style)
00079 copy_style(g.styles.default, normal_edge_style)
00080 copy_style(g.styles.default, selected_edge_style)
00081 copy_style(g.styles.default, graph_circle)
00082 copy_style(g.styles.default, container)
00083 copy_style(g.styles.default, container_selected)
00084
00085 graph_circle.fill = self.context.color(.96, .96, .96, .96)
00086 graph_circle.stroke = self.context.color(.8, .8, .8, 1.)
00087 graph_circle.strokewidth = 3
00088 graph_circle.fontsize = 24
00089 graph_circle.textwidth = 800
00090 graph_circle.text = self.context.color(.5, .5, .5, 1.)
00091
00092 container.fill = self.context.color(255./255, 204./255, 102./255., .4)
00093 container.node = g.styles.important.node
00094
00095 container_selected.fill = self.context.color(255./255, 204./255, 102./255., 1.)
00096 container_selected.node = g.styles.important.node
00097
00098 selected_style.text = text_color
00099 selected_edge_style.stroke = self.context.color(0.80, 0.00, 0.00, 0.75)
00100 selected_edge_style.strokewidth = 1.0
00101
00102 active_node_style.text = text_color
00103 active_node_style.fill = self.context.color(153./255, 255./255, 51/255, .75)
00104 active_node_style.strokewidth = 3
00105
00106 old_outcome_style.text = text_color
00107 old_outcome_style.fill = self.context.color(153./255, 255./255, 51/255, .4)
00108
00109 self.radii_increment = 150
00110 self.fsm_start_color = 1.
00111 self.fsm_end_color = .96
00112 self.fsm_stroke_color = .85
00113 self.fsm_current_context_node = None
00114 self.fsm_dclick_cb = None
00115
00116 self.right_clicked = None
00117 self.dx = 0.
00118 self.dy = 0.
00119 self.tx = 0.
00120 self.ty = 0.
00121
00122
00123 def set_node_style(self, node_name, style):
00124 self.gve.node(node_name).style = style
00125 self.gve.layout.refresh()
00126
00127 def get_node_style(self, node_name):
00128 return self.gve.node(node_name).style
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 def _background_drag(self, properties_dict):
00144 mouse_pose = properties_dict['MOUSEX'], properties_dict['MOUSEY']
00145
00146 if properties_dict['rightdown']:
00147 if not self.right_clicked:
00148 self.right_clicked = mouse_pose
00149 else:
00150 self.tx = mouse_pose[0] - self.right_clicked[0]
00151 self.ty = mouse_pose[1] - self.right_clicked[1]
00152 else:
00153
00154 self.right_clicked = None
00155 self.dx += self.tx
00156 self.dy += self.ty
00157 self.ty = 0.
00158 self.tx = 0.
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 def setup(self):
00178 self.times = {}
00179 self.times['draw'] = 0.
00180 self.times['check'] = 0.
00181 self.times['iter'] = 0
00182
00183
00184 def draw(self, properties_dict):
00185 START_TIME = time.time()
00186 self.context.size(properties_dict['width'], properties_dict['height'])
00187 cx = self.context
00188 g = self.gve
00189
00190
00191 for n in g.nodes:
00192 if properties_dict['selected_node'] == n.id:
00193 self.set_node_style(n.id, 'selected')
00194 else:
00195 self.set_node_style(n.id, 'normal')
00196
00197 if self.graph_model.get_start_state() == n.id:
00198 if self.get_node_style(n.id) == 'selected':
00199 self.set_node_style(n.id, 'important')
00200 else:
00201 self.set_node_style(n.id, 'marked')
00202
00203 if hasattr(self.graph_model.get_state(n.id), 'get_child'):
00204 if self.get_node_style(n.id) == 'selected':
00205 self.set_node_style(n.id, 'container_selected')
00206 else:
00207 self.set_node_style(n.id, 'container')
00208
00209 if self.graph_model.is_running():
00210 if not self.graph_model.sm_thread.has_key('current_states'):
00211 print 'KEYS!', self.graph_model.sm_thread.keys()
00212 if self.graph_model.sm_thread['current_states'] != None and \
00213 (len(set(self.graph_model.sm_thread['current_states']).intersection(set([n.id]))) > 0):
00214 self.set_node_style(n.id, 'active_node')
00215
00216 if self.graph_model.get_last_outcome() != None:
00217 outcome, t = self.graph_model.get_last_outcome()
00218 if outcome == n.id:
00219 if time.time() - t < 10.:
00220 self.set_node_style(n.id, 'old_outcome')
00221
00222
00223
00224 draw_func = None
00225
00226
00227 def draw_selected():
00228 if properties_dict['selected_edge'] == None:
00229 return
00230 cx = self.context
00231 g = self.gve
00232
00233 edge = properties_dict['selected_edge']
00234 x0, y0 = edge.node1.x, edge.node1.y
00235 x1, y1 = edge.node2.x, edge.node2.y
00236 coordinates = lambda x, y, d, a: (x+math.cos(math.radians(a))*d, y+math.sin(math.radians(a))*d)
00237
00238
00239 a = math.degrees(math.atan2(y1-y0, x1-x0))
00240
00241 r = edge.node2.r
00242 d = math.sqrt(pow(x1-x0, 2) + pow(y1-y0, 2))
00243 x00, y00 = coordinates(x0, y0, r+1, a)
00244 x01, y01 = coordinates(x0, y0, d-r-1, a)
00245
00246
00247 p1 = [x00, y00]
00248 p2 = [x01, y01]
00249 cx.fill()
00250 cx.strokewidth(1.0)
00251 cx.stroke(1., 153./255., 0, .75)
00252 cx.beginpath(p1[0], p1[1])
00253 cx.lineto(p2[0], p2[1])
00254 path = cx.endpath(False)
00255 gs.edge_arrow(g.styles[edge.node1.style], path, edge, radius=10)
00256 cx.drawpath(path)
00257
00258 def draw_fsm_circles():
00259 g = self.gve
00260
00261
00262 coords = []
00263 [coords.append([n.x, n.y]) for n in g.nodes]
00264 coords = np.matrix(coords).T
00265 centroid = np.median(coords, 1)
00266 if len(coords) == 0:
00267 return
00268
00269
00270 radius = np.max(np.power(np.sum(np.power((coords - centroid), 2), 0), .5)) + gm.GraphModel.NODE_RADIUS*2
00271 radius = max(radius, 200.)
00272 container_style = g.styles.graph_circle
00273 container_stroke = container_style.stroke
00274
00275
00276
00277 stack = copy.copy(properties_dict['fsm_stack'])
00278
00279
00280 largest_radii = radius + len(stack) * self.radii_increment
00281 color = self.fsm_start_color
00282 if len(stack) > 0:
00283 color_incre = (self.fsm_start_color - self.fsm_end_color) / len(stack)
00284
00285
00286 for el in stack:
00287
00288 name = el.model.document.get_name()
00289
00290
00291 stack_node = graph.node(g, radius = largest_radii, id = name)
00292 stack_node.x, stack_node.y = centroid[0,0], centroid[1,0]
00293 el.graph_node = stack_node
00294 container_style.fill = self.context.color(color, color, color, 1.)
00295 container_style.stroke = self.context.color(self.fsm_stroke_color, self.fsm_stroke_color, 1.)
00296 gs.node(container_style, stack_node, g.alpha)
00297
00298
00299 node_label_node_ = graph.node(g, radius = largest_radii, id = name)
00300 node_label_node_.x, node_label_node_.y = centroid[0,0], centroid[1,0] - largest_radii
00301 gs.node_label(container_style, node_label_node_, g.alpha)
00302
00303 color -= color_incre
00304 largest_radii -= self.radii_increment
00305
00306
00307
00308
00309
00310 graph_name_node = graph.node(g, radius=radius, id = properties_dict['name'])
00311 graph_name_node.x, graph_name_node.y = centroid[0,0], centroid[1,0]
00312 self.fsm_current_context_node = graph_name_node
00313 container_style.fill = self.context.color(self.fsm_end_color, self.fsm_end_color, self.fsm_end_color, 1.)
00314 container_style.stroke = container_stroke
00315 gs.node(container_style, graph_name_node, g.alpha)
00316
00317
00318 node_label_node = graph.node(g, radius=radius, id = properties_dict['name'])
00319 node_label_node.x, node_label_node.y = centroid[0,0], centroid[1,0] - radius
00320 gs.node_label(container_style, node_label_node, g.alpha)
00321
00322 def detect_fsm_click():
00323 def in_node(x, y, n):
00324 return (abs(x - n.x) < n.r) and (abs(y - n.y) < n.r)
00325
00326 mousex_g = self.context._ns['MOUSEX'] - self.gve.x
00327 mousey_g = self.context._ns['MOUSEY'] - self.gve.y
00328 if self.context._ns['mousedoubleclick'] and len(properties_dict['fsm_stack']) > 0:
00329 if not in_node(mousex_g, mousey_g, self.fsm_current_context_node):
00330 stack = copy.copy(properties_dict['fsm_stack'])
00331 stack.reverse()
00332 selected_el = None
00333 for el in stack:
00334 if in_node(mousex_g, mousey_g, el.graph_node):
00335
00336 selected_el = el
00337 break
00338
00339
00340 if selected_el != None and self.fsm_dclick_cb != None:
00341 self.fsm_dclick_cb(selected_el)
00342
00343 def final_func():
00344 draw_selected()
00345 detect_fsm_click()
00346
00347 CHECK_TIME = time.time()
00348 self._background_drag(properties_dict)
00349 properties_dict['MOUSEX'] -= self.dx+self.tx
00350 properties_dict['MOUSEY'] -= self.dy+self.ty
00351 g.draw(dx=self.dx+self.tx, dy=self.dy+self.ty, directed=True, traffic=False, user_draw_start=draw_fsm_circles, user_draw_final=final_func)
00352
00353 DRAW_TIME = time.time()
00354
00355 total_draw = DRAW_TIME - CHECK_TIME
00356 total_check = CHECK_TIME - START_TIME
00357 self.times['draw'] += total_draw
00358 self.times['check'] +- total_check
00359 self.times['iter'] += 1
00360