/[ascend]/trunk/pygtk/canvas/blockitem.py
ViewVC logotype

Contents of /trunk/pygtk/canvas/blockitem.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1979 - (show annotations) (download) (as text)
Sat Jan 10 00:21:37 2009 UTC (13 years, 7 months ago) by jpye
File MIME type: text/x-python
File size: 7821 byte(s)
Basic MODEL export functionality now in place for canvas.
Still needs lots of cleaning up though.

1
2 from gaphas.constraint import LineConstraint, LessThanConstraint, EqualsConstraint, Constraint, _update, BalanceConstraint
3 from gaphas.item import Line, SW, NE, NW, SE, Item, Handle
4 from gaphas.util import *
5 from gaphas.connector import PointPort, VariablePoint
6 from gaphas.solver import solvable, WEAK, NORMAL, STRONG, VERY_STRONG
7 from gaphas.state import observed, reversible_method, reversible_pair, reversible_property, disable_dispatching
8 from gaphas.geometry import distance_rectangle_point
9
10 from blockport import BlockPort
11 from blockinstance import PORT_IN, PORT_OUT
12
13 class ElementNoPorts(Item):
14 """
15 This is a copy of the Element class, but without the declaration
16 of the LinePorts in the __init__ method. It will be proposed to the
17 Gaphor team that the Element class be modified like this, because
18 there is quite a lot of useful code aside from the LinePort definition.
19 """
20
21 def __init__(self, width=10, height=10):
22 super(ElementNoPorts, self).__init__()
23 self._handles = [ h(strength=VERY_STRONG) for h in [Handle]*4 ]
24
25 handles = self._handles
26 h_nw = handles[NW]
27 h_ne = handles[NE]
28 h_sw = handles[SW]
29 h_se = handles[SE]
30
31 # no element ports by default
32 self._ports = []
33
34 # setup constraints
35 self.constraint(horizontal=(h_nw.pos, h_ne.pos))
36 self.constraint(horizontal=(h_se.pos, h_sw.pos))
37 self.constraint(vertical=(h_nw.pos, h_sw.pos))
38 self.constraint(vertical=(h_se.pos, h_ne.pos))
39
40 # create minimal size constraints
41 self._c_min_w = self.constraint(left_of=(h_nw.pos, h_se.pos), delta=10)
42 self._c_min_h = self.constraint(above=(h_nw.pos, h_se.pos), delta=10)
43
44 # set width/height when minimal size constraints exist
45 self.width = width
46 self.height = height
47
48
49 def setup_canvas(self):
50 super(ElementNoPorts, self).setup_canvas()
51
52 # Set width/height explicitly, so the element will maintain it
53 self.width = self.width
54 self.height = self.height
55
56 def _set_width(self, width):
57 """
58 >>> b=ElementNoPorts()
59 >>> b.width = 20
60 >>> b.width
61 20.0
62 >>> b._handles[NW].x
63 Variable(0, 40)
64 >>> b._handles[SE].x
65 Variable(20, 40)
66 """
67 if width < self.min_width:
68 width = self.min_width
69 h = self._handles
70 h[SE].x = h[NW].x + width
71
72
73 def _get_width(self):
74 """
75 Width of the box, calculated as the distance from the left and
76 right handle.
77 """
78 h = self._handles
79 return float(h[SE].x) - float(h[NW].x)
80
81 width = property(_get_width, _set_width)
82
83 def _set_height(self, height):
84 """
85 >>> b=ElementNoPorts()
86 >>> b.height = 20
87 >>> b.height
88 20.0
89 >>> b.height = 2
90 >>> b.height
91 10.0
92 >>> b._handles[NW].y
93 Variable(0, 40)
94 >>> b._handles[SE].y
95 Variable(10, 40)
96 """
97 if height < self.min_height:
98 height = self.min_height
99 h = self._handles
100 h[SE].y = h[NW].y + height
101
102 def _get_height(self):
103 """
104 Height.
105 """
106 h = self._handles
107 return float(h[SE].y) - float(h[NW].y)
108
109 height = property(_get_height, _set_height)
110
111 @observed
112 def _set_min_width(self, min_width):
113 """
114 Set minimal width.
115 """
116 if min_width < 0:
117 raise ValueError, 'Minimal width cannot be less than 0'
118
119 self._c_min_w.delta = min_width
120 if self.canvas:
121 self.canvas.solver.request_resolve_constraint(self._c_min_w)
122
123 min_width = reversible_property(lambda s: s._c_min_w.delta, _set_min_width)
124
125 @observed
126 def _set_min_height(self, min_height):
127 """
128 Set minimal height.
129 """
130 if min_height < 0:
131 raise ValueError, 'Minimal height cannot be less than 0'
132
133 self._c_min_h.delta = min_height
134 if self.canvas:
135 self.canvas.solver.request_resolve_constraint(self._c_min_h)
136
137 min_height = reversible_property(lambda s: s._c_min_h.delta, _set_min_height)
138
139
140 def point(self, pos):
141 """
142 Distance from the point (x, y) to the item.
143 """
144 h = self._handles
145 hnw, hse = h[NW], h[SE]
146 return distance_rectangle_point(map(float, (hnw.x, hnw.y, hse.x, hse.y)), pos)
147
148
149 class BlockItem(ElementNoPorts):
150 """
151 This is an ASCEND 'block' in the canvas-based modeller. The block will have
152 sets of input and output ports to which connector lines can be 'glued'.
153 The block will also have a corresponding ASCEND MODEL type, and a name
154 which will be used in ASCEND to refer to this block. Each of the ports will
155 be special visual elements, but note that these are not 'handles', because
156 they can not be used to resize/modify the element.
157 """
158
159 def __init__(self, width=64, height=64):
160 super(BlockItem, self).__init__(width, height)
161
162 def draw(self, context):
163 """
164 We want all ports within ASCEND to have a common appearance, so we
165 implement the drawing of ports here, and allow sub-classes of BlockItem
166 to implement the drawing of the other parts of the block, including the
167 outline etc.
168
169 Connected ports will be coloured red, other ports will be pale blue.
170 """
171 c = context.cairo
172 phalfsize = 3
173 for p in self._ports:
174 if hasattr(p,"point"):
175 c.rectangle(p.point.x - phalfsize, p.point.y - phalfsize, 2*phalfsize, 2*phalfsize)
176 #if p.connected_to is None:
177 c.set_source_rgba(0.8,0.8,1, 0.8)
178 #else:
179 # c.set_source_rgba(1,0,0,1)
180 c.fill_preserve()
181 c.set_source_rgb(0.8,0.8,0)
182 c.stroke()
183
184 # removing the 'glue' method now, as ports are now built in to gaphas.
185
186 def pre_update(self,context):
187 #print "PRE-UPDATE BLOCK"
188 pass
189
190 class DefaultBlockItem(BlockItem):
191 """
192 This is a 'default block' with a certain number of input and output ports
193 shown depending on the values sent to __init__. It is drawn as a simple
194 box with the input ports on the left and the output ports on the right.
195
196 @TODO Not clear yet whether blocks with 'custom' representations should have
197 as their parent class: this class or BlockItem.
198 """
199
200 def __init__(self, blockinstance):
201
202 self.blockinstance = blockinstance
203 super(DefaultBlockItem, self).__init__(64, 64)
204
205 eq = EqualsConstraint
206 bal = BalanceConstraint
207 handles = self._handles
208 h_nw = handles[NW]
209 h_ne = handles[NE]
210 h_sw = handles[SW]
211 h_se = handles[SE]
212
213 ninputs = len(blockinstance.blocktype.inputs)
214 noutputs = len(blockinstance.blocktype.outputs)
215 ii, oi = (0,0) # input and output index counters
216 _ports = []
217 for i in self.blockinstance.ports:
218 p = BlockPort(blockinstance, i)
219 if self.blockinstance.ports[i].type is PORT_IN:
220 self._constraints.append(eq(p.point.x, h_nw.x))
221 self._constraints.append(bal(band=(h_nw.y, h_sw.y),v=p.point.y, balance=(0.5 + ii)/ninputs))
222 ii += 1
223 elif self.blockinstance.ports[i].type is PORT_OUT:
224 self._constraints.append(eq(p.point.x, h_ne.x))
225 self._constraints.append(bal(band=(h_ne.y,h_se.y),v=p.point.y, balance=(0.5 + oi)/noutputs))
226 oi += 1
227 else:
228 raise RuntimeError("Unknown port type")
229 _ports.append(p)
230
231 self._ports = _ports
232
233 def draw(self, context):
234 # draw the box itself
235 c = context.cairo
236 nw = self._handles[NW]
237 c.rectangle(nw.x, nw.y, self.width, self.height)
238 if context.hovered:
239 c.set_source_rgba(.8,.8,1, .8)
240 else:
241 c.set_source_rgba(1,1,1, .8)
242 c.fill_preserve()
243 c.set_source_rgb(0,0,0.8)
244 c.stroke()
245
246 text_center(c,self.width/2,self.height/2,self.blockinstance.name)
247
248 # now the draw the ports using the base class
249 super(DefaultBlockItem, self).draw(context)
250

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22