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_SwitchNode.h"
21 #include "YACSPrs_Def.h"
23 #include "QxGraph_Canvas.h"
24 #include "QxGraph_Prs.h"
26 #include "SUIT_ResourceMgr.h"
32 using namespace YACS::ENGINE;
37 YACSPrs_SwitchNode::YACSPrs_SwitchNode( SUIT_ResourceMgr* theMgr, QCanvas* theCanvas, YACS::HMI::SubjectNode* theSNode ):
38 YACSPrs_InlineNode(theMgr, theCanvas, theSNode, false)
40 setNodeColor(SWITCHNODE_COLOR);
41 setNodeSubColor(SWITCHNODE_SUBCOLOR);
43 setStoreColor(nodeColor());
44 setStoreSubColor(nodeSubColor());
46 myTitlePixmap = myMgr->loadPixmap( "YACSPrs", QObject::tr( "ICON_TITLE_RARROW" ));
48 //updatePorts(); // will be called in moveBy(...) function
49 moveBy(2*HOOKPOINT_SIZE+NODEBOUNDARY_MARGIN,2*HOOKPOINT_SIZE+2*TITLE_HEIGHT+NODEBOUNDARY_MARGIN);
55 YACSPrs_SwitchNode::~YACSPrs_SwitchNode()
59 int YACSPrs_SwitchNode::rtti() const
61 return 0;//YACSPrs_Canvas::Rtti_SwitchNode;
64 QPointArray YACSPrs_SwitchNode::constructAreaPoints(int theW, int theH) const
68 if ( isControlDMode() )
70 aPnts = QPointArray(4);
71 aPnts[0] = QPoint((int)x(), (int)y()) + QPoint(-NODEBOUNDARY_MARGIN,-NODEBOUNDARY_MARGIN);
72 aPnts[1] = aPnts[0] + QPoint(theW, 0) + QPoint(NODEBOUNDARY_MARGIN,0);
73 aPnts[2] = aPnts[1] + QPoint(0, theH) + QPoint(0,NODEBOUNDARY_MARGIN);
74 aPnts[3] = aPnts[0] + QPoint(0, theH) + QPoint(0,NODEBOUNDARY_MARGIN);
76 else if ( isFullDMode() )
78 int aCorner = 2*TITLE_HEIGHT;
80 aPnts = QPointArray(5);
81 QPoint p((int)x(), (int)y());
82 aPnts[0] = p + QPoint(-NODEBOUNDARY_MARGIN,0);
83 aPnts[1] = p + QPoint(theW/2, -aCorner) + QPoint(0,-NODEBOUNDARY_MARGIN);
84 aPnts[2] = p + QPoint(theW, 0) + QPoint(NODEBOUNDARY_MARGIN,0);
85 aPnts[3] = aPnts[2] + QPoint(0, theH) + QPoint(0,NODEBOUNDARY_MARGIN/2);
86 aPnts[4] = p + QPoint(0, theH) + QPoint(-NODEBOUNDARY_MARGIN,NODEBOUNDARY_MARGIN/2);
92 void YACSPrs_SwitchNode::updatePorts(bool theForce)
94 bool aDisp = isVisible();
97 bool withCreate = theForce;
102 myPortHeight = 2*PORT_MARGIN;
106 myPortList.setAutoDelete(true);
107 //myPortList.clear();
109 QPtrList<YACSPrs_LabelPort> aDeletePortList;
110 for (YACSPrs_Port* aPort = myPortList.first(); aPort; aPort = myPortList.next())
112 if( YACSPrs_LabelPort* aLabelPort = dynamic_cast<YACSPrs_LabelPort*>( aPort ) )
114 aDeletePortList.append( aLabelPort );
119 for (YACSPrs_Port* aPort = aDeletePortList.first(); aPort; aPort = aDeletePortList.next())
120 myPortList.remove( aPort );
123 // Switch node has only 1 input port: its name is 'select',
124 // its type is 'int',
125 // its value is a number of active case (i.e. the case to execute)
126 // Switch node has no output ports, but in presentation we want to display a switch cases with
127 // its IDs (the number of cases and its IDs are set by user at creation process of switch node )
128 // as a 'label' ports. Each 'label' port connects with help of 'case' link to 'Master' hook
129 // of the node, which is set to this case ID.
131 if ( myPortList.isEmpty() ) withCreate = true;
135 QRect r = getBodyRect();
136 int aPRectWidth = (int)(r.width()/2) - 2*PORT_MARGIN;
137 if ( aPRectWidth < PORT_WIDTH ) aPRectWidth = PORT_WIDTH;
139 int ix = r.x() + PORT_MARGIN + 1;
140 int iy = r.y() + PORT_MARGIN;// + 1;
141 int ox = ix + aPRectWidth + 2*PORT_MARGIN;
142 int oy = r.y() + PORT_MARGIN;// + 1;
145 { // create (and update)
146 // 'select' input port (name, type (and value) of the port will set in YACSPrs_InOutPort from port engine)
147 Switch* aSEngine = dynamic_cast<Switch*>( getEngine() );
150 bool isConditionPortCreated = false;
151 InputPort* aConditionPort = aSEngine->edGetConditionPort();
152 for (YACSPrs_Port* aPort = myPortList.first(); aPort; aPort = myPortList.next())
154 if( !aPort->getName().compare( QString( aConditionPort->getName() ) ) )
156 isConditionPortCreated = true;
160 if( !isConditionPortCreated )
162 YACSPrs_InOutPort* anInPort = new YACSPrs_InOutPort(myMgr,canvas(),aConditionPort,this);
163 anInPort->setPortRect(QRect(ix, iy, aPRectWidth, PORT_HEIGHT));
164 anInPort->setColor(nodeSubColor());
165 anInPort->setStoreColor(nodeSubColor());
166 myPortList.append(anInPort);
169 // get a set of internal case nodes
170 std::list<Node*> aNodes = aSEngine->edGetDirectDescendants();
171 if ( aNodes.empty() )
172 myPortHeight += PORT_HEIGHT;
175 std::list<Node*>::iterator aNodesIter = aNodes.begin();
178 Node* aDefaultNode = aSEngine->getChildByShortName(Switch::DEFAULT_NODE_NAME);
180 int aMinCaseId, aMaxCaseId;
181 aMinCaseId = aMaxCaseId = aSEngine->getRankOfNode(*aNodesIter);
182 // a list of case nodes ordered from minimum to maximum case id
183 std::list<Node*> aCaseNodes;
184 for (; aNodesIter != aNodes.end(); aNodesIter++)
186 if ( *aNodesIter == aDefaultNode) continue;
188 // less than min => push front
189 if ( aMinCaseId >= aSEngine->getRankOfNode(*aNodesIter) ) {
190 aCaseNodes.push_front(*aNodesIter);
191 aMinCaseId = aSEngine->getRankOfNode(*aNodesIter);
194 else if ( aMinCaseId < aSEngine->getRankOfNode(*aNodesIter)
196 aMaxCaseId > aSEngine->getRankOfNode(*aNodesIter) ) {
197 std::list<Node*>::iterator aCaseNodesIter = aCaseNodes.begin();
198 for (std::list<Node*>::iterator anIt = aCaseNodesIter;
199 anIt++ != aCaseNodes.end();
200 aCaseNodesIter++, anIt = aCaseNodesIter) {
201 if ( aSEngine->getRankOfNode(*aNodesIter) >= aSEngine->getRankOfNode(*aCaseNodesIter)
203 aSEngine->getRankOfNode(*aNodesIter) <= aSEngine->getRankOfNode(*anIt) ) {
204 aCaseNodes.insert(anIt,*aNodesIter);
209 // more than max => push back
210 else if ( aMaxCaseId <= aSEngine->getRankOfNode(*aNodesIter) ) {
211 aCaseNodes.push_back(*aNodesIter);
212 aMaxCaseId = aSEngine->getRankOfNode(*aNodesIter);
216 aCaseNodes.push_back(aDefaultNode);
219 std::list<Node*>::iterator aCaseNodesIter = aCaseNodes.begin();
220 for (; aCaseNodesIter != aCaseNodes.end(); aCaseNodesIter++)
221 { // (in fact we have to get from user number of switch cases)
222 // output label ports
223 YACSPrs_LabelPort* anOutPort = new YACSPrs_LabelPort(myMgr,canvas(),*aCaseNodesIter,this,
224 true,aSEngine->getRankOfNode(*aCaseNodesIter));
225 anOutPort->setPortRect(QRect(ox, oy+heightIncr, aPRectWidth, PORT_HEIGHT));
226 anOutPort->setColor(nodeSubColor().dark(140));
227 anOutPort->setStoreColor(nodeSubColor().dark(140));
228 if ( *aCaseNodesIter == aDefaultNode) anOutPort->setName(Switch::DEFAULT_NODE_NAME);
229 myPortList.append(anOutPort);
230 heightIncr += PORT_HEIGHT+PORT_SPACE;
233 myPortHeight += aNodes.size()*PORT_HEIGHT + (aNodes.size()-1)*PORT_SPACE;
240 for (aPort = myPortList.first(); aPort; aPort = myPortList.next())
242 YACSPrs_InOutPort* anIOPort = dynamic_cast<YACSPrs_InOutPort*>( aPort );
245 if ( !anIOPort->isGate() && anIOPort->isInput() )
246 { // input data (i.e. not Gate) ports
247 anIOPort->setPortRect(QRect(ix, iy, aPRectWidth, PORT_HEIGHT), !isSelfMoving(), myArea);
248 iy += PORT_HEIGHT+PORT_SPACE;
252 { // not YACSPrs_InOutPort => it is YACSPrs_LabelPort (output!) => we not need to dynamic cast
253 aPort->setPortRect(QRect(ox, oy, aPRectWidth, PORT_HEIGHT), !isSelfMoving(), myArea);
254 oy += PORT_HEIGHT+PORT_SPACE;
260 // can update gates only after body height will be defined
261 bool createGates = withCreate;
262 for (YACSPrs_Port* aPort = myPortList.first(); aPort; aPort = myPortList.next())
264 if( YACSPrs_InOutPort* anIOPort = dynamic_cast<YACSPrs_InOutPort*>( aPort ) )
266 if ( anIOPort->isGate() )
267 { // gate ports are already created - we should only update them
273 updateGates(createGates);
275 if (theForce && myPointMaster)
277 QPoint aPnt = getConnectionMasterPoint();
278 myPointMaster->setCoords(aPnt.x(), aPnt.y());
284 void YACSPrs_SwitchNode::drawPort(QPainter& thePainter)
286 QRect r = getBodyRect();
287 r.setHeight(r.height()+1);
289 thePainter.drawRect(r);
290 int x0 = (r.left() + r.right())/2;
291 thePainter.drawLine(x0, r.top(), x0, r.bottom());
293 int aRRectWidth = (x0 - r.left() - 2*PORT_MARGIN - 2*PORT_SPACE)/3;
294 int aRRectWidthLabel = x0 - r.left() - 2*PORT_MARGIN;
295 QRect aTRect = getTitleRect();
296 int aXRnd = aTRect.width()*myXRnd/aRRectWidth;
297 int aXRndLabel = aTRect.width()*myXRnd/aRRectWidthLabel;
298 int aYRnd = aTRect.height()*myYRnd/PORT_HEIGHT;
301 for (aPort = myPortList.first(); aPort; aPort = myPortList.next())
303 YACSPrs_InOutPort* anInPort = dynamic_cast<YACSPrs_InOutPort*>( aPort );
304 YACSPrs_LabelPort* anOutPort = dynamic_cast<YACSPrs_LabelPort*>( aPort );
305 if ( anInPort && !anInPort->isGate() )
306 aPort->draw(thePainter, aXRnd, aYRnd);
308 aPort->draw(thePainter, aXRndLabel, aYRnd);
312 void YACSPrs_SwitchNode::drawFrame(QPainter& thePainter)
314 QRect aRect = getRect();
315 QRect aTRect = getTitleRect();
316 int aXRnd = aTRect.width()*myXRnd/aRect.width();
317 int aYRnd = aTRect.height()*myYRnd/aRect.height();
319 if ( isControlDMode() )
320 thePainter.drawRoundRect(aRect,aXRnd,aYRnd);
321 else if ( isFullDMode() )
323 QPen savedP = thePainter.pen();
324 thePainter.setPen(NoPen);
326 // calculate width and height for acrs
327 int w = 4*(aXRnd*aRect.width()/100)/3;
328 int h = 4*(aYRnd*aRect.height()/100)/3;
330 // draw chords without pen
331 thePainter.drawChord( aRect.x(),aRect.y(), w,h, 90*16, 90*16 );
332 thePainter.drawChord( aRect.right()-w+1,aRect.y(), w,h, 0*16, 90*16 );
333 thePainter.drawChord( aRect.right()-w+1,aRect.bottom()-h+1, w,h, 270*16, 90*16 );
334 thePainter.drawChord( aRect.x(),aRect.bottom()-h+1, w,h, 180*16, 90*16 );
336 //thePainter.drawRoundRect(aRect,aXRnd,aYRnd);
337 int aCorner = 2*TITLE_HEIGHT;
338 QPoint aP1(aRect.x()+(w-1)/2,aRect.y());
339 QPoint aP2(aRect.x()+aRect.width()/2,aRect.y()-aCorner);
340 QPoint aP3(aRect.right()-(w-1)/2,aRect.y());
341 QPoint aP4(aRect.right(),aRect.y()+h/2-1);
342 QPoint aP5(aRect.right(),aRect.bottom()-h/2+1);
343 QPoint aP6(aRect.right()-(w-1)/2,aRect.bottom());
344 QPoint aP7(aRect.x()+(w-1)/2,aRect.bottom());
345 QPoint aP8(aRect.x(),aRect.bottom()-h/2+1);
346 QPoint aP9(aRect.x(),aRect.y()+h/2-1);
349 aP1.x(),aP1.y(), aP2.x(),aP2.y(), aP3.x(),aP3.y(), aP4.x(),aP4.y(),
350 aP5.x(),aP5.y(), aP6.x(),aP6.y(), aP7.x(),aP7.y(), aP8.x(),aP8.y(), aP9.x(),aP9.y());
351 thePainter.drawPolygon( aPA );
352 thePainter.setPen(savedP);
355 thePainter.drawArc( aRect.x(),aRect.y(), w,h, 90*16, 90*16 );
356 thePainter.drawArc( aRect.right()-w+1,aRect.y(), w,h, 0*16, 90*16 );
357 thePainter.drawArc( aRect.right()-w+1,aRect.bottom()-h+1, w,h, 270*16, 90*16 );
358 thePainter.drawArc( aRect.x(),aRect.bottom()-h+1, w,h, 180*16, 90*16 );
360 // draw line segments
361 thePainter.drawLine(aP1,aP2);
362 thePainter.drawLine(aP2,aP3);
363 thePainter.drawLine(aP4,aP5);
364 thePainter.drawLine(aP6,aP7);
365 thePainter.drawLine(aP8,aP9);
368 QRect aTPRect(aRect.x()+aRect.width()/2-aCorner/3, aRect.y()-(aCorner-NODE_MARGIN)/2-aCorner/3,
369 2*aCorner/3, 2*aCorner/3);
370 thePainter.drawPixmap(aTPRect,myTitlePixmap);
373 // draw bounding nodes' polygon if node is currently selected
374 if ( isSelected() ) drawBoundary(thePainter,(isFullDMode() ? 3 : 2));