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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2074 - (hide annotations) (download) (as text)
Fri Sep 4 06:50:08 2009 UTC (10 years, 2 months ago) by arijit
File MIME type: text/x-python
File size: 8179 byte(s)
Google SoC 2009 Project : Implementation of canvas based modeller for energy systems
1 jpye 1970
2 jpye 1945 from gaphas.constraint import LineConstraint, LessThanConstraint, EqualsConstraint, Constraint, _update, BalanceConstraint
3 jpye 1970 from gaphas.item import Line, SW, NE, NW, SE, Item, Handle
4 jpye 1945 from gaphas.util import *
5 jpye 1970 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 jpye 1945
10 jpye 1979 from blockport import BlockPort
11     from blockinstance import PORT_IN, PORT_OUT
12    
13 jpye 1970 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 jpye 1945
21 jpye 1970 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 jpye 1945 """
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 jpye 1970 """
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 jpye 1945 phalfsize = 3
173 jpye 1970 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 jpye 1945 c.set_source_rgba(0.8,0.8,1, 0.8)
178 jpye 1970 #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 jpye 1945
184 jpye 1970 # removing the 'glue' method now, as ports are now built in to gaphas.
185 jpye 1945
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 jpye 1970
196     @TODO Not clear yet whether blocks with 'custom' representations should have
197     as their parent class: this class or BlockItem.
198 jpye 1945 """
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 jpye 1979 ninputs = len(blockinstance.blocktype.inputs)
214     noutputs = len(blockinstance.blocktype.outputs)
215     ii, oi = (0,0) # input and output index counters
216 jpye 1970 _ports = []
217 jpye 1979 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 jpye 1970 _ports.append(p)
230 jpye 1945
231 jpye 1970 self._ports = _ports
232    
233 jpye 1945 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 arijit 2074 try:
240     c.set_source_rgb(self.blockinstance.color_r,self.blockinstance.color_g,self.blockinstance.color_b)
241     except AttributeError:
242     c.set_source_rgb(1,1,1)
243    
244     #c.set_source_rgba(.8,.8,1, .8)
245 jpye 1945 else:
246 arijit 2074 #c.set_source_rgba(1,1,1, .8)
247     try:
248     c.set_source_rgb(2*self.blockinstance.color_r,2*self.blockinstance.color_g,2*self.blockinstance.color_b)
249     except AttributeError:
250     c.set_source_rgb(1,1,1)
251    
252 jpye 1945 c.fill_preserve()
253 arijit 2074 c.set_source_rgb(0,0,0)
254 jpye 1945 c.stroke()
255    
256     text_center(c,self.width/2,self.height/2,self.blockinstance.name)
257    
258     # now the draw the ports using the base class
259     super(DefaultBlockItem, self).draw(context)
260 jpye 1954

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