1 |
import cairo |
2 |
from gaphas.tool import HandleTool |
3 |
from port import * |
4 |
|
5 |
class PortConnectingHandleTool(HandleTool): |
6 |
""" |
7 |
This is a HandleTool which supports the connection of lines to the Ports |
8 |
of Blocks, for the purpose of building up process flow diagrams, control |
9 |
diagrams, etc, for the proposed canvas-based modeller of ASCEND. |
10 |
""" |
11 |
|
12 |
def glue(self, view, item, handle, wx, wy): |
13 |
""" |
14 |
This allows the tool to glue a handle to any connectable Port of a Block. |
15 |
The distance from the item to the handle is determined in canvas |
16 |
coordinates, using a 10 pixel glue distance. |
17 |
|
18 |
Returns the closest Port that is within the glue distance. |
19 |
""" |
20 |
if handle and not handle.connectable: |
21 |
return |
22 |
|
23 |
# Make glue distance depend on the zoom ratio (should be about 10 pixels) |
24 |
inverse = cairo.Matrix(*view.matrix) |
25 |
inverse.invert() |
26 |
#glue_distance, dummy = inverse.transform_distance(10, 0) |
27 |
glue_distance = 10 |
28 |
glue_port = None |
29 |
glue_point = None |
30 |
#print "Gluing..." |
31 |
for i in view.canvas.get_all_items(): |
32 |
if not hasattr(i,'ports'): |
33 |
continue |
34 |
if not i is item: |
35 |
#print "Trying glue to",i |
36 |
v2i = view.get_matrix_v2i(i).transform_point |
37 |
ix, iy = v2i(wx, wy) |
38 |
distance, port = i.glue(item, handle, ix, iy) |
39 |
# Transform distance to world coordinates |
40 |
#distance, dumy = matrix_i2w(i).transform_distance(distance, 0) |
41 |
if not port is None and distance <= glue_distance: |
42 |
glue_distance = distance |
43 |
i2v = view.get_matrix_i2v(i).transform_point |
44 |
glue_point = i2v(port.x, port.y) |
45 |
glue_port = port |
46 |
else: |
47 |
pass |
48 |
#print "i is item" |
49 |
if glue_point and handle and item: |
50 |
v2i = view.get_matrix_v2i(item).transform_point |
51 |
handle.x, handle.y = v2i(*glue_point) |
52 |
#print "Found glue point ",handle.x,handle.y |
53 |
return glue_port |
54 |
|
55 |
def connect(self, view, item, handle, wx, wy): |
56 |
""" |
57 |
Connect a handle to a port. 'item' is the line to which the handle |
58 |
belongs; wx and wy are the location of the cursor, so we run the 'glue' |
59 |
routine to find the desired gluing point, then make the connection to |
60 |
the object which 'glue' returns, which will be a Port object (in the |
61 |
context of this tool). |
62 |
|
63 |
In this "method" the following assumptios are made: |
64 |
1. Only ``Port``s of ``Block``s will accept connections from handles. |
65 |
2. The only items with connectable handles are ``Line``s |
66 |
|
67 |
""" |
68 |
|
69 |
# create a special local handle_disconnect function |
70 |
def handle_disconnect(): |
71 |
try: |
72 |
view.canvas.solver.remove_constraint(handle.connection_data) |
73 |
except KeyError: |
74 |
print 'constraint was already removed for', item, handle |
75 |
pass # constraint was alreasy removed |
76 |
else: |
77 |
print 'constraint removed for', item, handle |
78 |
handle.connected_port.connected_to = None |
79 |
handle.connection_data = None |
80 |
handle.connection_port = None |
81 |
handle.connected_to = None |
82 |
|
83 |
# Remove disconnect handler: |
84 |
handle.disconnect = lambda: 0 |
85 |
|
86 |
#print 'Handle.connect', view, item, handle, wx, wy |
87 |
glue_port = self.glue(view, item, handle, wx, wy) |
88 |
|
89 |
if glue_port and hasattr(handle,'connected_port') and handle.connected_port is glue_port: |
90 |
try: |
91 |
view.canvas.solver.remove_constraint(handle.connection_data) |
92 |
except KeyError: |
93 |
pass |
94 |
else: |
95 |
# ie no glue_port found, or the handle connected to something else |
96 |
if handle.connected_to: |
97 |
handle.disconnect() |
98 |
|
99 |
if glue_port: |
100 |
if isinstance(glue_port, Port): |
101 |
#print "Gluing to port",glue_port |
102 |
|
103 |
#print "handle.pos =",handle.pos |
104 |
#print "glue_port =",glue_port |
105 |
#print "glue_port.pos = ",glue_port.pos |
106 |
#print "glue_port.block =",glue_port.block |
107 |
|
108 |
handle.connection_data = PointConstraint( |
109 |
B=CanvasProjection(handle.pos,item) |
110 |
,A=CanvasProjection(glue_port.pos, glue_port.block) |
111 |
) |
112 |
view.canvas.solver.add_constraint(handle.connection_data) |
113 |
#glue_port.block._constraints.append(handle.connection_data) |
114 |
|
115 |
handle.connected_to = glue_port.block |
116 |
handle.connected_port = glue_port |
117 |
handle.disconnect = handle_disconnect |
118 |
glue_port.connected_to = handle |
119 |
|
120 |
def disconnect(self, view, item, handle): |
121 |
if handle.connected_to: |
122 |
print 'Handle.disconnect', view, item, handle |
123 |
view.canvas.solver.remove_constraint(handle.connection_data) |
124 |
|