import cairo from gaphas.tool import HandleTool from port import * class PortConnectingHandleTool(HandleTool): """ This is a HandleTool which supports the connection of lines to the Ports of Blocks, for the purpose of building up process flow diagrams, control diagrams, etc, for the proposed canvas-based modeller of ASCEND. """ def glue(self, view, item, handle, wx, wy): """ This allows the tool to glue a handle to any connectable Port of a Block. The distance from the item to the handle is determined in canvas coordinates, using a 10 pixel glue distance. Returns the closest Port that is within the glue distance. """ if handle and not handle.connectable: return # Make glue distance depend on the zoom ratio (should be about 10 pixels) inverse = cairo.Matrix(*view.matrix) inverse.invert() #glue_distance, dummy = inverse.transform_distance(10, 0) glue_distance = 10 glue_port = None glue_point = None #print "Gluing..." for i in view.canvas.get_all_items(): if not hasattr(i,'ports'): continue if not i is item: #print "Trying glue to",i v2i = view.get_matrix_v2i(i).transform_point ix, iy = v2i(wx, wy) distance, port = i.glue(item, handle, ix, iy) # Transform distance to world coordinates #distance, dumy = matrix_i2w(i).transform_distance(distance, 0) if not port is None and distance <= glue_distance: glue_distance = distance i2v = view.get_matrix_i2v(i).transform_point glue_point = i2v(port.x, port.y) glue_port = port else: pass #print "i is item" if glue_point and handle and item: v2i = view.get_matrix_v2i(item).transform_point handle.x, handle.y = v2i(*glue_point) #print "Found glue point ",handle.x,handle.y return glue_port def connect(self, view, item, handle, wx, wy): """ Connect a handle to a port. 'item' is the line to which the handle belongs; wx and wy are the location of the cursor, so we run the 'glue' routine to find the desired gluing point, then make the connection to the object which 'glue' returns, which will be a Port object (in the context of this tool). In this "method" the following assumptios are made: 1. Only ``Port``s of ``Block``s will accept connections from handles. 2. The only items with connectable handles are ``Line``s """ # create a special local handle_disconnect function def handle_disconnect(): try: view.canvas.solver.remove_constraint(handle.connection_data) except KeyError: print 'constraint was already removed for', item, handle pass # constraint was alreasy removed else: print 'constraint removed for', item, handle handle.connected_port.connected_to = None handle.connection_data = None handle.connection_port = None handle.connected_to = None # Remove disconnect handler: handle.disconnect = lambda: 0 #print 'Handle.connect', view, item, handle, wx, wy glue_port = self.glue(view, item, handle, wx, wy) if glue_port and hasattr(handle,'connected_port') and handle.connected_port is glue_port: try: view.canvas.solver.remove_constraint(handle.connection_data) except KeyError: pass else: # ie no glue_port found, or the handle connected to something else if handle.connected_to: handle.disconnect() if glue_port: if isinstance(glue_port, Port): #print "Gluing to port",glue_port #print "handle.pos =",handle.pos #print "glue_port =",glue_port #print "glue_port.pos = ",glue_port.pos #print "glue_port.block =",glue_port.block handle.connection_data = PointConstraint( B=CanvasProjection(handle.pos,item) ,A=CanvasProjection(glue_port.pos, glue_port.block) ) view.canvas.solver.add_constraint(handle.connection_data) #glue_port.block._constraints.append(handle.connection_data) handle.connected_to = glue_port.block handle.connected_port = glue_port handle.disconnect = handle_disconnect glue_port.connected_to = handle def disconnect(self, view, item, handle): if handle.connected_to: print 'Handle.disconnect', view, item, handle view.canvas.solver.remove_constraint(handle.connection_data)