Salome HOME
copy tag mergefrom_BR_V0_1_CC_Salome_04oct07
[modules/yacs.git] / src / prs / YACSPrs_LoopNode.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "YACSPrs_LoopNode.h"
21 #include "YACSPrs_Def.h"
22
23 #include "SUIT_ResourceMgr.h"
24
25 #include <qpainter.h>
26
27 #include <ForLoop.hxx>
28 #include <WhileLoop.hxx>
29
30 using namespace YACS::ENGINE;
31
32 /*!
33   Constructor
34 */
35 YACSPrs_LoopNode::YACSPrs_LoopNode( SUIT_ResourceMgr* theMgr, QCanvas* theCanvas, YACS::ENGINE::Node* theNode, const bool& thePortUpdate ):
36   YACSPrs_InlineNode(theMgr, theCanvas, theNode, false)
37 {
38   setNodeColor(LOOPNODE_COLOR);
39   setNodeSubColor(LOOPNODE_SUBCOLOR);
40   setBracketColor(LOOPNODE_BRACKETCOLOR);
41
42   setStoreColor(nodeColor());
43   setStoreSubColor(nodeSubColor());
44   myStoreBracketColor = myBracketColor;
45
46   myTopPixmap = myMgr->loadPixmap( "YACSPrs", QObject::tr( "ICON_TITLE_RARROW" ));
47   myBottomPixmap = myMgr->loadPixmap( "YACSPrs", QObject::tr( "ICON_TITLE_LARROW" ));
48   
49   if ( thePortUpdate ) {
50     //updatePorts(); // will be called in moveBy(...) function
51     moveBy(3*TITLE_HEIGHT/2, 3*TITLE_HEIGHT/2);
52   }
53 }
54
55 /*!
56   Destructor
57 */
58 YACSPrs_LoopNode::~YACSPrs_LoopNode()
59 {
60 }
61
62 void YACSPrs_LoopNode::select(const QPoint& theMousePos, const bool toSelect)
63 {
64   if ( toSelect ) 
65   {
66     // unhilight the item under the mouse cursor
67     hilight(theMousePos, false);
68
69     bool isOnPort = false;
70     if (getBodyRect().contains(theMousePos, true) || getGateRect().contains(theMousePos, true))
71     {
72       // process ports
73       QPtrList<YACSPrs_Port> aPortList = getPortList();
74       for (YACSPrs_Port* aPort = aPortList.first(); aPort; aPort = aPortList.next()) {
75         if (aPort->getPortRect().contains(theMousePos, true)) {
76           isOnPort = true;
77           if ( aPort != mySelectedPort )
78           {
79             if ( mySelectedPort )
80             {
81               mySelectedPort->setSelected(false);
82               mySelectedPort->setColor(mySelectedPort->storeColor(), false, true, true);
83             }
84             else
85             {
86               setSelected(false);
87               setBracketColor( myStoreBracketColor );
88               setNodeSubColor( storeSubColor(), true );
89             }
90             aPort->setSelected(true);
91             aPort->setColor(aPort->Color().dark(130), false, true, true);
92             mySelectedPort = aPort;
93           }
94           break;
95         }
96       }
97     }
98     
99     if ( !isOnPort )
100     {
101       if ( mySelectedPort )
102       {
103         mySelectedPort->setSelected(false);
104         mySelectedPort = 0;
105       }
106       
107       if ( storeSubColor().dark(130) != nodeSubColor() )
108       {
109         myStoreBracketColor = myBracketColor;
110         setStoreSubColor( nodeSubColor() );
111         
112         setSelected(true);
113         setBracketColor( bracketColor().dark(130) );
114         setNodeSubColor( nodeSubColor().dark(130), true );
115       }
116     }
117   }
118   else
119   {
120     if ( mySelectedPort ) {
121       mySelectedPort->setSelected(false);
122       mySelectedPort->setColor(mySelectedPort->storeColor(), false, true, true);
123       mySelectedPort = 0;
124     }
125     else {
126       setSelected(false);
127       setBracketColor( myStoreBracketColor );
128       setNodeSubColor( storeSubColor(), true );
129     }
130   }
131 }
132
133 int YACSPrs_LoopNode::rtti() const
134 {
135   return 0;//YACSPrs_Canvas::Rtti_LoopNode;
136 }
137
138 QPointArray YACSPrs_LoopNode::constructAreaPoints(int theW, int theH) const
139 {
140   int h = theH-1;
141
142   int aCorner = 3*TITLE_HEIGHT/2;
143
144   QPointArray aPnts(8);
145   QPoint p((int)x(), (int)y());
146   p = p + QPoint(-NODEBOUNDARY_MARGIN,0);
147   aPnts[0] = p;
148   aPnts[1] = p + QPoint(aCorner, -aCorner) + QPoint(NODEBOUNDARY_MARGIN,-NODEBOUNDARY_MARGIN);
149   aPnts[2] = aPnts[1] + QPoint(theW, 0) + QPoint(NODEBOUNDARY_MARGIN,0);
150   aPnts[3] = p + QPoint(theW, 0) + QPoint(NODEBOUNDARY_MARGIN,0);
151   aPnts[4] = aPnts[3] + QPoint(0, h) + QPoint(0,-NODEBOUNDARY_MARGIN/2);
152   aPnts[5] = aPnts[4] + QPoint(-aCorner, aCorner) + QPoint(-NODEBOUNDARY_MARGIN,NODEBOUNDARY_MARGIN);
153   aPnts[6] = aPnts[5] + QPoint(-theW, 0) + QPoint(-NODEBOUNDARY_MARGIN,0);
154   aPnts[7] = p + QPoint(0, h) + QPoint(0,-NODEBOUNDARY_MARGIN/2);
155   return aPnts;
156 }
157
158 void YACSPrs_LoopNode::setBracketColor(const QColor& theColor, bool theUpdate)
159 {
160   myBracketColor = theColor;
161   if ( canvas() && theUpdate )
162   { 
163     canvas()->setChanged(boundingRect());
164     canvas()->update();
165   }
166 }
167
168 void YACSPrs_LoopNode::updatePorts()
169 {
170   bool aDisp = isVisible();
171   if (aDisp) hide();
172   
173   // ForLoop and WhileLoop nodes have only 1 input port.
174   // ForLoop : its name is 'nsteps' ,
175   //           its type is 'int',
176   //           its value is a number of iterations.
177   // WhileLoop : its name is 'condition' ,
178   //             its type is 'bool',
179   //             its value is a while condition, iteration process breaks when condition switch to false.
180   // ForLoop and WhileLoop nodes have no output ports, but in presentation we want to display a 'label' port with
181   // name 'Body'. This 'label' port connects with help of 'case' link to 'Master' hook
182   // of the node, which is set as an internal node of the loop.
183
184   bool withCreate = false;
185   if ( myPortList.isEmpty() ) withCreate = true;
186
187   QRect r = getBodyRect();
188   int aPRectWidth = (int)(r.width()/2) - 2*PORT_MARGIN;
189   if ( aPRectWidth < PORT_WIDTH ) aPRectWidth = PORT_WIDTH;
190   
191   int ix = r.x() + PORT_MARGIN + 1;
192   int iy = r.y() + PORT_MARGIN;// + 1;
193   int ox = ix + aPRectWidth + 2*PORT_MARGIN;
194   int oy = r.y() + PORT_MARGIN;// + 1;
195
196   ForLoop* aFLoop = dynamic_cast<ForLoop*>( myEngine );
197   WhileLoop* aWLoop = 0;
198
199   if ( withCreate )
200   { // create (and update)
201     // 'nsteps'/'condition' input port (name, type (and value) of the port will set in YACSPrs_InOutPort from port engine)
202     YACSPrs_InOutPort* anInPort = 0;
203
204     if ( aFLoop )
205       anInPort = new YACSPrs_InOutPort(myMgr,canvas(),aFLoop->edGetNbOfTimesInputPort(),this);
206     else
207     {
208       aWLoop = dynamic_cast<WhileLoop*>( myEngine );
209       if ( aWLoop )
210         anInPort = new YACSPrs_InOutPort(myMgr,canvas(),aWLoop->edGetConditionPort(),this);
211     }
212     
213     if ( anInPort )
214     {
215       anInPort->setPortRect(QRect(ix, iy, aPRectWidth, PORT_HEIGHT));
216       anInPort->setColor(nodeSubColor());
217       anInPort->setStoreColor(nodeSubColor());
218       myPortList.append(anInPort);
219     }
220     
221     if ( aFLoop || aWLoop )
222     {
223       // get a set of internal loop nodes (in fact in ForLoop and WhileLoop we have only one internal node)
224       std::set<Node*> aNodes = aFLoop ? aFLoop->edGetDirectDescendants() : aWLoop->edGetDirectDescendants();
225       std::set<Node*>::iterator aNodesIter = aNodes.begin();
226       for (; aNodesIter != aNodes.end(); aNodesIter++)
227       { // output label port
228         YACSPrs_LabelPort* anOutPort = new YACSPrs_LabelPort(myMgr,canvas(),*aNodesIter,this);
229         anOutPort->setPortRect(QRect(ox, oy, aPRectWidth, PORT_HEIGHT));
230         anOutPort->setColor(nodeSubColor().dark(140));
231         anOutPort->setStoreColor(nodeSubColor().dark(140));
232         myPortList.append(anOutPort);
233         myPortHeight += PORT_HEIGHT;
234       }
235     }
236   }
237   else
238   { // only update
239     YACSPrs_Port* aPort;
240     for (aPort = myPortList.first(); aPort; aPort = myPortList.next())
241     { 
242       YACSPrs_InOutPort* anInPort = dynamic_cast<YACSPrs_InOutPort*>( aPort );
243       if ( anInPort )
244       { 
245         if ( !anInPort->isGate() && anInPort->isInput() )
246         { // input data (i.e. not Gate) ports
247           anInPort->setPortRect(QRect(ix, iy, aPRectWidth, PORT_HEIGHT), !isSelfMoving(), myArea);
248           iy += PORT_HEIGHT+PORT_SPACE;
249         }
250       }
251       else
252       { // not YACSPrs_InOutPort => it is YACSPrs_LabelPort => we not need to dynamic cast
253         aPort->setPortRect(QRect(ox, oy, aPRectWidth, PORT_HEIGHT), !isSelfMoving(), myArea);
254         oy += PORT_HEIGHT+PORT_SPACE;
255       }
256     }
257   }
258     
259   // can update gates only after body height will be defined
260   updateGates(withCreate);
261
262   if (aDisp) show();
263 }
264
265 int YACSPrs_LoopNode::maxWidth() const
266 {
267   return YACSPrs_ElementaryNode::maxWidth() - 4*HOOKPOINT_SIZE + ( ( 4*HOOKPOINT_SIZE > 3*TITLE_HEIGHT ) ? 4*HOOKPOINT_SIZE-3*TITLE_HEIGHT : 0 );
268 }
269
270 void YACSPrs_LoopNode::drawPort(QPainter& thePainter)
271 {
272   QRect r = getBodyRect();
273   r.setHeight(r.height()+1);
274
275   thePainter.drawRect(r);
276   int x0 = (r.left() + r.right())/2;
277   thePainter.drawLine(x0, r.top(), x0, r.bottom());
278
279   int aRRectWidth = (x0 - r.left() - 2*PORT_MARGIN - 2*PORT_SPACE)/3;
280   int aRRectWidthLabel = x0 - r.left() - 2*PORT_MARGIN;
281   QRect aTRect = getTitleRect();
282   int aXRnd = aTRect.width()*myXRnd/aRRectWidth;
283   int aXRndLabel = aTRect.width()*myXRnd/aRRectWidthLabel;
284   int aYRnd = aTRect.height()*myYRnd/PORT_HEIGHT;
285
286   YACSPrs_Port* aPort;
287   for (aPort = myPortList.first(); aPort; aPort = myPortList.next())
288   {
289     YACSPrs_InOutPort* anInPort = dynamic_cast<YACSPrs_InOutPort*>( aPort );
290     YACSPrs_LabelPort* anOutPort = dynamic_cast<YACSPrs_LabelPort*>( aPort );
291     if ( anInPort && !anInPort->isGate() )
292       aPort->draw(thePainter, aXRnd, aYRnd);
293     if ( anOutPort )
294       aPort->draw(thePainter, aXRndLabel, aYRnd);
295   } 
296 }
297
298 void YACSPrs_LoopNode::drawFrame(QPainter& thePainter)
299 {
300   QRect aRect = getRect();
301   QRect aTRect = getTitleRect();
302
303   thePainter.drawRect(aRect);
304
305   QBrush savedB = thePainter.brush();
306   thePainter.setBrush(bracketColor());
307
308   int aCorner =  3*TITLE_HEIGHT/2;
309   QPoint aP1(aRect.x(),            aRect.y());
310   QPoint aP2(aRect.x()+aCorner,    aRect.y()-aCorner);
311   QPoint aP3(aRect.right()+aCorner,aRect.y()-aCorner);
312   QPoint aP4(aRect.right(),        aRect.y());
313   QPoint aP5(aRect.x(),            aRect.bottom());
314   QPoint aP6(aRect.x()-aCorner,    aRect.bottom()+aCorner);
315   QPoint aP7(aRect.right()-aCorner,aRect.bottom()+aCorner);
316   QPoint aP8(aRect.right(),        aRect.bottom());
317   QPointArray aPAUp(4);
318   aPAUp.putPoints(0, 4, aP1.x(),aP1.y(), aP2.x(),aP2.y(), aP3.x(),aP3.y(), aP4.x(),aP4.y());
319   thePainter.drawPolygon( aPAUp );
320   QPointArray aPADown(4);
321   aPADown.putPoints(0, 4, aP5.x(),aP5.y(), aP6.x(),aP6.y(), aP7.x(),aP7.y(), aP8.x(),aP8.y());
322   thePainter.drawPolygon( aPADown );
323
324   thePainter.setBrush(savedB);
325
326   // draw top pixmap
327   QRect aTPRect(aRect.x()+aRect.width()/2-aCorner/3, aRect.y()-aCorner/2-aCorner/3,
328                 2*aCorner/3, 2*aCorner/3);
329   thePainter.drawPixmap(aTPRect,myTopPixmap);
330
331   // draw bottom pixmap
332   QRect aBPRect(aRect.x()+aRect.width()/2-aCorner/3, aRect.bottom()+aCorner/2-aCorner/3,
333                 2*aCorner/3, 2*aCorner/3);
334   thePainter.drawPixmap(aBPRect,myBottomPixmap);
335
336   // draw bounding nodes' polygon if node is currently selected
337   if ( isSelected() ) drawBoundary(thePainter,5);
338 }
339
340 QPoint YACSPrs_LoopNode::getConnectionMasterPoint()
341 {
342   QRect aRect = getRect();
343   return QPoint(aRect.left()+aRect.width()/2, aRect.bottom()+3*TITLE_HEIGHT/2);
344 }
345
346 bool YACSPrs_LoopNode::checkArea(double dx, double dy)
347 {
348   // for constraint nodes' moving inside the Bloc-->
349   if ( !myIsInBloc ) return true;
350
351   QRect aRect = boundingRect();
352   aRect.moveBy((int)dx, (int)dy);
353   aRect.setRect(aRect.x() - ( ( 2*HOOKPOINT_SIZE > 3*TITLE_HEIGHT/2 ) ? 2*HOOKPOINT_SIZE-3*TITLE_HEIGHT/2 : 0 ) + NODEBOUNDARY_MARGIN,
354                 aRect.y(), maxWidth(), maxHeight());
355   if ( myArea.isValid() && myArea.contains(aRect) )
356     return true;
357   return false;
358   // <--
359 }