1 // Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "YACSPrs_LoopNode.h"
21 #include "YACSPrs_Def.h"
23 #include "SUIT_ResourceMgr.h"
27 #include <ForLoop.hxx>
28 #include <WhileLoop.hxx>
30 using namespace YACS::ENGINE;
35 YACSPrs_LoopNode::YACSPrs_LoopNode( SUIT_ResourceMgr* theMgr, QCanvas* theCanvas,
36 YACS::HMI::SubjectNode* theSNode, const bool& thePortUpdate ):
37 YACSPrs_InlineNode(theMgr, theCanvas, theSNode, false)
39 setNodeColor(LOOPNODE_COLOR);
40 setNodeSubColor(LOOPNODE_SUBCOLOR);
41 setBracketColor(LOOPNODE_BRACKETCOLOR);
43 setStoreColor(nodeColor());
44 setStoreSubColor(nodeSubColor());
45 myStoreBracketColor = myBracketColor;
47 myTopPixmap = myMgr->loadPixmap( "YACSPrs", QObject::tr( "ICON_TITLE_RARROW" ));
48 myBottomPixmap = myMgr->loadPixmap( "YACSPrs", QObject::tr( "ICON_TITLE_LARROW" ));
50 if ( thePortUpdate ) {
51 //updatePorts(); // will be called in moveBy(...) function
53 moveBy(3*TITLE_HEIGHT/2+NODEBOUNDARY_MARGIN, 3*TITLE_HEIGHT/2+NODEBOUNDARY_MARGIN);
54 else if ( isControlDMode() )
55 moveBy(2*HOOKPOINT_SIZE+NODEBOUNDARY_MARGIN,2*HOOKPOINT_SIZE+NODEBOUNDARY_MARGIN);
62 YACSPrs_LoopNode::~YACSPrs_LoopNode()
66 void YACSPrs_LoopNode::select(const QPoint& theMousePos, const bool toSelect)
70 // unhilight the item under the mouse cursor
71 hilight(theMousePos, false);
73 bool isOnPort = false;
74 if (getBodyRect().contains(theMousePos, true) || getGateRect().contains(theMousePos, true))
77 QPtrList<YACSPrs_Port> aPortList = getPortList();
78 for (YACSPrs_Port* aPort = aPortList.first(); aPort; aPort = aPortList.next()) {
79 if (aPort->getPortRect().contains(theMousePos, true)) {
81 if ( aPort != mySelectedPort )
85 mySelectedPort->setSelected(false);
86 mySelectedPort->setColor(mySelectedPort->storeColor(), false, true, true);
87 synchronize( mySelectedPort, false );
92 getSEngine()->select(false);
94 setBracketColor( myStoreBracketColor );
95 setNodeSubColor( storeSubColor(), true );
97 aPort->setSelected(true);
98 aPort->setColor(aPort->Color().dark(130), false, true, true);
99 mySelectedPort = aPort;
100 synchronize( mySelectedPort, true );
109 if ( mySelectedPort )
111 mySelectedPort->setSelected(false);
112 synchronize( mySelectedPort, false );
116 if ( storeSubColor().dark(130) != nodeSubColor() )
118 myStoreBracketColor = myBracketColor;
119 setStoreSubColor( nodeSubColor() );
122 getSEngine()->select(true);
124 setBracketColor( bracketColor().dark(130) );
125 setNodeSubColor( nodeSubColor().dark(130), true );
131 if ( mySelectedPort ) {
132 mySelectedPort->setSelected(false);
133 mySelectedPort->setColor(mySelectedPort->storeColor(), false, true, true);
134 synchronize( mySelectedPort, false );
139 getSEngine()->select(false);
141 setBracketColor( myStoreBracketColor );
142 setNodeSubColor( storeSubColor(), true );
147 int YACSPrs_LoopNode::rtti() const
149 return 0;//YACSPrs_Canvas::Rtti_LoopNode;
152 QPointArray YACSPrs_LoopNode::constructAreaPoints(int theW, int theH) const
156 if ( isControlDMode() )
158 aPnts = QPointArray(4);
159 aPnts[0] = QPoint((int)x(), (int)y()) + QPoint(-NODEBOUNDARY_MARGIN,-NODEBOUNDARY_MARGIN);
160 aPnts[1] = aPnts[0] + QPoint(theW, 0) + QPoint(NODEBOUNDARY_MARGIN,0);
161 aPnts[2] = aPnts[1] + QPoint(0, theH) + QPoint(0,NODEBOUNDARY_MARGIN);
162 aPnts[3] = aPnts[0] + QPoint(0, theH) + QPoint(0,NODEBOUNDARY_MARGIN);
164 else if ( isFullDMode() )
168 int aCorner = 3*TITLE_HEIGHT/2;
170 aPnts = QPointArray(8);
171 QPoint p((int)x(), (int)y());
172 p = p + QPoint(-NODEBOUNDARY_MARGIN,0);
174 aPnts[1] = p + QPoint(aCorner, -aCorner) + QPoint(NODEBOUNDARY_MARGIN,-NODEBOUNDARY_MARGIN);
175 aPnts[2] = aPnts[1] + QPoint(theW, 0) + QPoint(NODEBOUNDARY_MARGIN,0);
176 aPnts[3] = p + QPoint(theW, 0) + QPoint(NODEBOUNDARY_MARGIN,0);
177 aPnts[4] = aPnts[3] + QPoint(0, h) + QPoint(0,-NODEBOUNDARY_MARGIN/2);
178 aPnts[5] = aPnts[4] + QPoint(-aCorner, aCorner) + QPoint(-NODEBOUNDARY_MARGIN,NODEBOUNDARY_MARGIN);
179 aPnts[6] = aPnts[5] + QPoint(-theW, 0) + QPoint(-NODEBOUNDARY_MARGIN,0);
180 aPnts[7] = p + QPoint(0, h) + QPoint(0,-NODEBOUNDARY_MARGIN/2);
186 void YACSPrs_LoopNode::setBracketColor(const QColor& theColor, bool theUpdate)
188 myBracketColor = theColor;
189 if ( canvas() && theUpdate )
191 canvas()->setChanged(boundingRect());
196 void YACSPrs_LoopNode::updatePorts(bool theForce)
198 bool aDisp = isVisible();
201 bool withCreate = theForce;
206 myPortHeight = 2*PORT_MARGIN;
210 myPortList.setAutoDelete(true);
211 //myPortList.clear();
213 QPtrList<YACSPrs_LabelPort> aDeletePortList;
214 for (YACSPrs_Port* aPort = myPortList.first(); aPort; aPort = myPortList.next())
216 if( YACSPrs_LabelPort* aLabelPort = dynamic_cast<YACSPrs_LabelPort*>( aPort ) )
218 aDeletePortList.append( aLabelPort );
223 for (YACSPrs_Port* aPort = aDeletePortList.first(); aPort; aPort = aDeletePortList.next())
224 myPortList.remove( aPort );
227 // ForLoop and WhileLoop nodes have only 1 input port.
228 // ForLoop : its name is 'nsteps' ,
229 // its type is 'int',
230 // its value is a number of iterations.
231 // WhileLoop : its name is 'condition' ,
232 // its type is 'bool',
233 // its value is a while condition, iteration process breaks when condition switch to false.
234 // ForLoop and WhileLoop nodes have no output ports, but in presentation we want to display a 'label' port with
235 // name 'Body'. This 'label' port connects with help of 'case' link to 'Master' hook
236 // of the node, which is set as an internal node of the loop.
238 if ( myPortList.isEmpty() ) withCreate = true;
242 QRect r = getBodyRect();
243 int aPRectWidth = (int)(r.width()/2) - 2*PORT_MARGIN;
244 if ( aPRectWidth < PORT_WIDTH ) aPRectWidth = PORT_WIDTH;
246 int ix = r.x() + PORT_MARGIN + 1;
247 int iy = r.y() + PORT_MARGIN;// + 1;
248 int ox = ix + aPRectWidth + 2*PORT_MARGIN;
249 int oy = r.y() + PORT_MARGIN;// + 1;
251 ForLoop* aFLoop = dynamic_cast<ForLoop*>( getEngine() );
252 WhileLoop* aWLoop = dynamic_cast<WhileLoop*>( getEngine() );
255 { // create (and update)
256 // 'nsteps'/'condition' input port (name, type (and value) of the port will set in YACSPrs_InOutPort from port engine)
257 bool isConditionPortCreated = false;
258 InputPort* aConditionPort = 0;
260 aConditionPort = aFLoop->edGetNbOfTimesInputPort();
262 aConditionPort = aWLoop->edGetConditionPort();
264 for (YACSPrs_Port* aPort = myPortList.first(); aPort; aPort = myPortList.next())
266 if( !aPort->getName().compare( QString( aConditionPort->getName() ) ) )
268 isConditionPortCreated = true;
272 if( !isConditionPortCreated )
274 YACSPrs_InOutPort* anInPort = 0;
276 anInPort = new YACSPrs_InOutPort(myMgr,canvas(),aFLoop->edGetNbOfTimesInputPort(),this);
278 anInPort = new YACSPrs_InOutPort(myMgr,canvas(),aWLoop->edGetConditionPort(),this);
282 anInPort->setPortRect(QRect(ix, iy, aPRectWidth, PORT_HEIGHT));
283 anInPort->setColor(nodeSubColor());
284 anInPort->setStoreColor(nodeSubColor());
285 myPortList.append(anInPort);
289 if ( aFLoop || aWLoop )
291 // get a set of internal loop nodes (in fact in ForLoop and WhileLoop we have only one internal node)
292 std::list<Node*> aNodes = aFLoop ? aFLoop->edGetDirectDescendants() : aWLoop->edGetDirectDescendants();
293 if ( aNodes.empty() )
294 myPortHeight += PORT_HEIGHT;
297 std::list<Node*>::iterator aNodesIter = aNodes.begin();
298 for (; aNodesIter != aNodes.end(); aNodesIter++)
299 { // output label port
300 YACSPrs_LabelPort* anOutPort = new YACSPrs_LabelPort(myMgr,canvas(),*aNodesIter,this);
301 anOutPort->setPortRect(QRect(ox, oy, aPRectWidth, PORT_HEIGHT));
302 anOutPort->setColor(nodeSubColor().dark(140));
303 anOutPort->setStoreColor(nodeSubColor().dark(140));
304 myPortList.append(anOutPort);
305 myPortHeight += PORT_HEIGHT;
313 for (aPort = myPortList.first(); aPort; aPort = myPortList.next())
315 YACSPrs_InOutPort* anInPort = dynamic_cast<YACSPrs_InOutPort*>( aPort );
318 if ( !anInPort->isGate() && anInPort->isInput() )
319 { // input data (i.e. not Gate) ports
320 anInPort->setPortRect(QRect(ix, iy, aPRectWidth, PORT_HEIGHT), !isSelfMoving(), myArea);
321 iy += PORT_HEIGHT+PORT_SPACE;
325 { // not YACSPrs_InOutPort => it is YACSPrs_LabelPort => we not need to dynamic cast
326 aPort->setPortRect(QRect(ox, oy, aPRectWidth, PORT_HEIGHT), !isSelfMoving(), myArea);
327 oy += PORT_HEIGHT+PORT_SPACE;
333 // can update gates only after body height will be defined
334 bool createGates = withCreate;
335 for (YACSPrs_Port* aPort = myPortList.first(); aPort; aPort = myPortList.next())
337 if( YACSPrs_InOutPort* anIOPort = dynamic_cast<YACSPrs_InOutPort*>( aPort ) )
339 if ( anIOPort->isGate() )
340 { // gate ports are already created - we should only update them
346 updateGates(createGates);
348 if (theForce && myPointMaster)
350 QPoint aPnt = getConnectionMasterPoint();
351 myPointMaster->setCoords(aPnt.x(), aPnt.y());
357 int YACSPrs_LoopNode::maxWidth() const
359 if ( isControlDMode() )
360 return YACSPrs_ElementaryNode::maxWidth();
362 // Full view mode as a default
363 return YACSPrs_ElementaryNode::maxWidth() - 4*HOOKPOINT_SIZE + ( ( 4*HOOKPOINT_SIZE > 3*TITLE_HEIGHT ) ? 4*HOOKPOINT_SIZE-3*TITLE_HEIGHT : 0 );
366 int YACSPrs_LoopNode::minX() const
368 return YACSPrs_ElementaryNode::minX() + 2*HOOKPOINT_SIZE - ( ( 2*HOOKPOINT_SIZE > 3*TITLE_HEIGHT/2 ) ?
373 int YACSPrs_LoopNode::maxX() const
375 return YACSPrs_ElementaryNode::maxX() - 2*HOOKPOINT_SIZE + ( ( 2*HOOKPOINT_SIZE > 3*TITLE_HEIGHT/2 ) ?
380 void YACSPrs_LoopNode::drawPort(QPainter& thePainter)
382 QRect r = getBodyRect();
383 r.setHeight(r.height()+1);
385 thePainter.drawRect(r);
386 int x0 = (r.left() + r.right())/2;
387 thePainter.drawLine(x0, r.top(), x0, r.bottom());
389 int aRRectWidth = (x0 - r.left() - 2*PORT_MARGIN - 2*PORT_SPACE)/3;
390 int aRRectWidthLabel = x0 - r.left() - 2*PORT_MARGIN;
391 QRect aTRect = getTitleRect();
392 int aXRnd = aTRect.width()*myXRnd/aRRectWidth;
393 int aXRndLabel = aTRect.width()*myXRnd/aRRectWidthLabel;
394 int aYRnd = aTRect.height()*myYRnd/PORT_HEIGHT;
397 for (aPort = myPortList.first(); aPort; aPort = myPortList.next())
399 YACSPrs_InOutPort* anInPort = dynamic_cast<YACSPrs_InOutPort*>( aPort );
400 YACSPrs_LabelPort* anOutPort = dynamic_cast<YACSPrs_LabelPort*>( aPort );
401 if ( anInPort && !anInPort->isGate() )
402 aPort->draw(thePainter, aXRnd, aYRnd);
404 aPort->draw(thePainter, aXRndLabel, aYRnd);
408 void YACSPrs_LoopNode::drawFrame(QPainter& thePainter)
410 QRect aRect = getRect();
411 QRect aTRect = getTitleRect();
413 thePainter.drawRect(aRect);
417 QBrush savedB = thePainter.brush();
418 thePainter.setBrush(bracketColor());
420 int aCorner = 3*TITLE_HEIGHT/2;
421 QPoint aP1(aRect.x(), aRect.y());
422 QPoint aP2(aRect.x()+aCorner, aRect.y()-aCorner);
423 QPoint aP3(aRect.right()+aCorner,aRect.y()-aCorner);
424 QPoint aP4(aRect.right(), aRect.y());
425 QPoint aP5(aRect.x(), aRect.bottom());
426 QPoint aP6(aRect.x()-aCorner, aRect.bottom()+aCorner);
427 QPoint aP7(aRect.right()-aCorner,aRect.bottom()+aCorner);
428 QPoint aP8(aRect.right(), aRect.bottom());
429 QPointArray aPAUp(4);
430 aPAUp.putPoints(0, 4, aP1.x(),aP1.y(), aP2.x(),aP2.y(), aP3.x(),aP3.y(), aP4.x(),aP4.y());
431 thePainter.drawPolygon( aPAUp );
432 QPointArray aPADown(4);
433 aPADown.putPoints(0, 4, aP5.x(),aP5.y(), aP6.x(),aP6.y(), aP7.x(),aP7.y(), aP8.x(),aP8.y());
434 thePainter.drawPolygon( aPADown );
436 thePainter.setBrush(savedB);
439 QRect aTPRect(aRect.x()+aRect.width()/2-aCorner/3, aRect.y()-aCorner/2-aCorner/3,
440 2*aCorner/3, 2*aCorner/3);
441 thePainter.drawPixmap(aTPRect,myTopPixmap);
443 // draw bottom pixmap
444 QRect aBPRect(aRect.x()+aRect.width()/2-aCorner/3, aRect.bottom()+aCorner/2-aCorner/3,
445 2*aCorner/3, 2*aCorner/3);
446 thePainter.drawPixmap(aBPRect,myBottomPixmap);
449 // draw bounding nodes' polygon if node is currently selected
450 if ( isSelected() ) drawBoundary(thePainter,5);
453 QPoint YACSPrs_LoopNode::getConnectionMasterPoint()
455 QRect aRect = getRect();
456 return QPoint(aRect.left()+aRect.width()/2, aRect.bottom()+3*TITLE_HEIGHT/2);
459 bool YACSPrs_LoopNode::checkArea(double dx, double dy)
461 // for constraint nodes' moving inside the Bloc-->
462 if ( !myIsInBloc ) return true;
464 QRect aRect = boundingRect();
465 aRect.moveBy((int)dx, (int)dy);
466 aRect.setRect(aRect.x() - ( ( 2*HOOKPOINT_SIZE > 3*TITLE_HEIGHT/2 ) ? 2*HOOKPOINT_SIZE-3*TITLE_HEIGHT/2 : 0 ) + NODEBOUNDARY_MARGIN,
467 aRect.y(), maxWidth(), maxHeight());
468 if ( myArea.isValid() && myArea.contains(aRect) )
474 bool YACSPrs_LoopNode::synchronize( YACSPrs_Port* port, const bool toSelect )
476 return YACSPrs_InOutPort::synchronize( port, toSelect );