1 // SUPERV SUPERVGUI : GUI for Supervisor component
3 // Copyright (C) 2003 CEA/DEN, EDF R&D
7 // File : SUPERVGUI_Link.cxx
8 // Author : Vitaly SMETANNIKOV
12 #include "SUPERVGUI_Graph.h"
13 #include "SUPERVGUI_Main.h"
14 #include "SUPERVGUI_Link.h"
18 #define SKETCH_CLR Qt::green
19 #define DRAW_CLR Qt::black
20 #define HLT_CLR Qt::magenta
21 #define CTRL_CLR Qt::red
27 // Prevents moving of several links at once
28 bool SUPERVGUI_Link::LinkIsMoving=false;
30 bool SUPERVGUI_Link::OrthoMode = false;
32 SUPERVGUI_Link* SUPERVGUI_Link::SelectedLink=0;
36 * If link is NULL - this must be defined later
38 SUPERVGUI_Link::SUPERVGUI_Link(SUPERVGUI_Graph* theGraph, SUPERV_Link theLink) {
46 myPntMovingState = false;
49 myTmpPen.setColor(SKETCH_CLR);
50 myTmpPen.setWidth(LINE_WIDTH);
54 if (!SUPERV_isNull(myEngine))
59 //**********************************************************************
60 SUPERVGUI_Link::~SUPERVGUI_Link() {
61 if (!SUPERV_isNull(myEngine)) {
62 disconnect(myGraph, 0, this, 0);
64 if (SelectedLink == this) SelectedLink=0;
65 emit linkDeleted(this);
69 //**********************************************************************
70 void SUPERVGUI_Link::setInputPort(SUPERVGUI_PortIn* thePortIn) {
72 myPortIn->setLinkPrs(this);
76 //**********************************************************************
77 void SUPERVGUI_Link::setInputPortES(SUPERVGUI_PortInESNode* thePortInES) {
78 myPortInES = thePortInES;
79 myPortInES->setLinkPrs(this);
82 //**********************************************************************
83 bool SUPERVGUI_Link::isESInputPort() {
90 //**********************************************************************
91 void SUPERVGUI_Link::destroyEngine() {
92 if (!SUPERV_isNull(myEngine)) {
97 //**********************************************************************
98 void SUPERVGUI_Link::setOutputPort(SUPERVGUI_PortOut* thePortOut){
99 myPortOut = thePortOut;
100 myPortOut->addLinkPrs(this);
104 //**********************************************************************
105 void SUPERVGUI_Link::addPoint(long theX, long theY) {
106 if (SUPERV_isNull(myEngine)) return;
108 if (myEngine->CoordsSize() <= 0) {
109 myEngine->AddCoord(1, theX, theY);
112 QPoint aPnt(theX, theY);
114 myEngine->Coords(1, aX, aY);
115 if (!isESInputPort()) {
116 if (distance(aPnt, myGraph->viewportToContents(myPortIn->getConnectPnt()),
117 QPoint(aX, aY)) <= 0) {
118 myEngine->AddCoord(1, theX, theY);
123 if (distance(aPnt, myGraph->viewportToContents(myPortInES->getConnectPnt()),
124 QPoint(aX, aY)) <= 0) {
125 myEngine->AddCoord(1, theX, theY);
132 for (i = 2; i <= myEngine->CoordsSize(); i++) {
133 myEngine->Coords(i, aNextX, aNextY);
134 if (distance(aPnt, QPoint(aX, aY),
135 QPoint(aNextX, aNextY)) <= 0) {
136 myEngine->AddCoord(i, theX, theY);
142 if (distance(aPnt, QPoint(aX, aY),
143 myGraph->viewportToContents(myPortOut->getConnectPnt())) <= 0) {
144 myEngine->AddCoord(myEngine->CoordsSize()+1, theX, theY);
152 //**********************************************************************
154 * Can be used only in Sketching mode
156 void SUPERVGUI_Link::addTmpPoint(QPoint thePnt) {
158 int aSize = myTmpPoints.size();
162 aPrevPnt = myTmpPoints[aSize-1];
164 aPrevPnt = myStartPort->getConnectPnt();
168 if (Abs(thePnt.x() - aPrevPnt.x()) >
169 Abs(thePnt.y() - aPrevPnt.y())) {
170 aNewPoint = QPoint(thePnt.x(), aPrevPnt.y());
172 aNewPoint = QPoint(aPrevPnt.x(), thePnt.y());
176 myPainter->drawLine(aPrevPnt, thePnt);
177 myPainter->moveTo(aPrevPnt);
178 myPainter->lineTo(aNewPoint);
179 myPainter->lineTo(thePnt);
181 myTmpPoints.push_back(aNewPoint);
183 myTmpPoints.push_back(thePnt);
187 //**********************************************************************
189 * Can be used only in Sketching mode
191 void SUPERVGUI_Link::delLastTmpPoint() {
192 int aSize = myTmpPoints.size();
194 QPoint aRemPnt = myTmpPoints[aSize-1];
198 aLastPnt = myTmpPoints[aSize-2];
200 aLastPnt = myStartPort->getConnectPnt();
202 myPainter->moveTo(aLastPnt);
203 myPainter->lineTo(aRemPnt);
204 myPainter->lineTo(myPrevPoint);
206 myPainter->drawLine(aLastPnt, myPrevPoint);
208 myTmpPoints.pop_back();
213 //**********************************************************************
214 void SUPERVGUI_Link::removeLastPoint() {
215 if (myEngine && (!SUPERV_isNull(myEngine)))
216 myEngine->RemoveCoord(myEngine->CoordsSize());
220 //**********************************************************************
221 void SUPERVGUI_Link::removePoint(int thePnt) {
222 if ((thePnt > -1) && (!SUPERV_isNull(myEngine))) {
224 myEngine->RemoveCoord(thePnt);
229 //**********************************************************************
233 void SUPERVGUI_Link::repaint() {
239 //**********************************************************************
241 * Paints or erases the link
242 * if toErase = true then it draws link by background color
244 void SUPERVGUI_Link::paint(bool toErase) {
245 if ((!myGraph) || (!myIsVisible)) return;
246 if (!myEngine && SUPERV_isNull(myEngine)) return;
247 // if (!isCreationComplete()) return;
249 QPainter aPainter(myGraph->viewport());
251 aDataPen.setWidth(LINE_WIDTH);
254 aDataPen.setColor(myGraph->viewport()->paletteBackgroundColor());
256 if (strcmp(myEngine->InPort()->Name(), "InVoid")==0)
257 aDataPen.setColor(CTRL_CLR);
259 aDataPen.setColor(DRAW_CLR);
261 aPainter.setPen(aDataPen);
266 //**********************************************************************
268 * Defines a pen and draws link using given painter
270 void SUPERVGUI_Link::paint(QPainter* thePainter, bool toErase) {
271 if ((!myGraph) || (!myIsVisible)) return;
272 if (!myEngine && SUPERV_isNull(myEngine)) return;
273 // if (!isCreationComplete()) return;
277 aDataPen.setWidth(LINE_WIDTH);
280 aDataPen.setColor(myGraph->viewport()->paletteBackgroundColor());
282 if (strcmp(myEngine->InPort()->Name(), "InVoid")==0)
283 aDataPen.setColor(CTRL_CLR);
285 aDataPen.setColor(DRAW_CLR);
287 thePainter->setPen(aDataPen);
288 drawLink(thePainter);
289 thePainter->restore();
293 //**********************************************************************
295 * Draws link using given painter
297 void SUPERVGUI_Link::drawLink(QPainter* thePainter) {
298 if (!myIsVisible) return;
299 if (!isESInputPort())
300 thePainter->moveTo(myPortIn->getConnectPnt());
302 thePainter->moveTo(myPortInES->getConnectPnt());
305 for (int i=0; i < myEngine->CoordsSize(); i++) {
306 myEngine->Coords(i+1, aX, aY);
307 aPnt = myGraph->contentsToViewport(QPoint(aX, aY));
308 thePainter->lineTo(aPnt);
309 thePainter->drawEllipse(aPnt.x()-PNT_SIZE/2, aPnt.y()-PNT_SIZE/2,
312 thePainter->lineTo(myPortOut->getConnectPnt());
316 //**********************************************************************
318 * Repaints whole link when it is sketching
320 void SUPERVGUI_Link::repaintSketch() {
321 if (!myStartPort) return;
322 if (!myPainter) return;
324 // myPainter->save();
325 //myPainter->setRasterOp(Qt::CopyROP);
326 myPainter->moveTo(myStartPort->getConnectPnt());
327 for (int i = 0; i< myTmpPoints.size(); i++) {
328 myPainter->lineTo(myGraph->contentsToViewport(myTmpPoints[i]));
330 myPainter->lineTo(myPrevPoint);
331 //myPainter->restore();
335 //**********************************************************************
337 * Drawing of non created link following to mouse pointer
339 void SUPERVGUI_Link::drawTo(QPoint thePnt) {
342 myStartPort = myPortIn;
344 myStartPort = myPortInES;
346 myStartPort = myPortOut;
351 myPainter = new QPainter(myGraph->viewport());
352 myPainter->setPen(myTmpPen);
353 myPainter->setRasterOp(Qt::XorROP);
354 myPrevPoint = myStartPort->getConnectPnt();
361 if (myTmpPoints.size() > 0)
362 aStartPnt = myGraph->contentsToViewport(myTmpPoints[myTmpPoints.size()-1]);
364 aStartPnt = myStartPort->getConnectPnt();
367 myPainter->drawLine(aStartPnt, myPrevPoint);
370 QPoint aNewPoint = myGraph->contentsToViewport(thePnt);
371 myPainter->drawLine(aStartPnt, aNewPoint);
372 myPrevPoint = aNewPoint;
377 //**********************************************************************
379 * Set link non visible
381 void SUPERVGUI_Link::setVisible(bool theVisible) {
382 myIsVisible = theVisible;
386 disconnect(myGraph, 0, this, 0);
391 //**********************************************************************
393 * Checks full definition of the link
395 bool SUPERVGUI_Link::isCreationComplete() {
396 bool aIsBoth = myPortIn && myPortOut;
397 if (myPortIn && myPortOut) {
398 SUPERV_Port aInPort = myPortIn->getPort();
399 QString aInNodeName(aInPort->Node()->Name());
400 SUPERV_Port aOutPort = myPortOut->getPort();
401 QString aOutNodeName(aOutPort->Node()->Name());
403 return (aInNodeName != aOutNodeName);
405 else if (myPortInES && myPortOut) {
406 SUPERV_Port aInPortES = myPortInES->getPort();
407 QString aInNodeName(aInPortES->Node()->Name());
408 SUPERV_Port aOutPort = myPortOut->getPort();
409 QString aOutNodeName(aOutPort->Node()->Name());
411 return (aInNodeName != aOutNodeName);
417 //**********************************************************************
419 * Abort creation of link
421 void SUPERVGUI_Link::abortCreation() {
422 LinkIsMoving = false;
425 //**********************************************************************
427 * Final procedure of link creation
429 bool SUPERVGUI_Link::createEngine() {
430 // clear temporary drawing
431 QPen aOldPen(myGraph->viewport()->paletteBackgroundColor(), LINE_WIDTH);
432 //check if myPainter not null
434 myPainter->setPen(aOldPen);
435 myPainter->setRasterOp(Qt::CopyROP);
438 if (myTmpPoints.size() > 0)
439 aStartPnt = myGraph->contentsToViewport(myTmpPoints[myTmpPoints.size()-1]);
441 aStartPnt = myStartPort->getConnectPnt();
443 myPainter->drawLine(aStartPnt, myPrevPoint);
450 if (!isESInputPort())
451 myEngine = myGraph->getMain()->getDataflow()->
452 Link(myPortOut->getPort(), myPortIn->getPort());
454 myEngine = myGraph->getMain()->getDataflow()->
455 Link(myPortOut->getPort(), myPortInES->getPort());
457 if (SUPERV_isNull(myEngine)) return false;
459 // remember all points
461 if (myStartPort == myPortOut) {
462 int aSize = myTmpPoints.size();
463 for (int i = aSize; i > 0; i--) {
464 aPnt = myTmpPoints[i-1];
465 myEngine->AddCoord(aSize+1-i, aPnt.x(), aPnt.y());
468 for (int i = 0; i < myTmpPoints.size(); i++) {
469 aPnt = myTmpPoints[i];
470 myEngine->AddCoord(i+1, aPnt.x(), aPnt.y());
473 LinkIsMoving = false;
475 // empty temporary resources
485 //**********************************************************************
486 void SUPERVGUI_Link::onMouseMove(QMouseEvent * theEvent) {
487 if (myPntMovingState) {
490 QPoint aPos = myGraph->contentsToViewport(theEvent->pos());
491 int aX = (aPos.x() > 0)? aPos.x(): 1;
492 int aY = (aPos.y() > 0)? aPos.y(): 1;
493 aX = (aX < myGraph->contentsWidth())? aX: myGraph->contentsWidth()-1;
494 aY = (aY < myGraph->contentsHeight())? aY: myGraph->contentsHeight()-1;
496 myMovedPnt = QPoint(aX, aY);
501 if (LinkIsMoving) return;
503 // Points highlighting
504 QPoint aPos = theEvent->pos();
505 if (myEngine->CoordsSize() > 0 ) {
507 bool aIsFound = false;
508 for (int i=0; i < myEngine->CoordsSize(); i++) {
509 myEngine->Coords(i+1, aX, aY);
512 aPos.y()) < (PNT_SIZE+2)) {
518 if (!aIsFound) myHltPnt = -1;
522 if (isSelected(aPos)) {
523 if (SelectedLink==0) {
524 QPen aNewPen(HLT_CLR, LINE_WIDTH);
525 QPainter aPainter(myGraph->viewport());
526 aPainter.setPen(aNewPen);
531 } else if (myIsSelected) {
532 myIsSelected = false;
533 if (SelectedLink == this) SelectedLink = 0;
539 //**********************************************************************
541 * For internal using only
542 * Draws segments by current Pen when point is moving
544 void SUPERVGUI_Link::drawSegments() {
545 myPainter->drawLine(myBeforePnt, myMovedPnt);
546 myPainter->drawLine(myMovedPnt, myAfterPnt);
547 myPainter->drawEllipse(myMovedPnt.x()-PNT_SIZE/2,
548 myMovedPnt.y()-PNT_SIZE/2,
553 //**********************************************************************
554 void SUPERVGUI_Link::onMousePress(QMouseEvent * theEvent) {
558 if (theEvent->button() != Qt::LeftButton) {
562 if (myHltPnt > -1) { // start point moving
564 if (!isESInputPort()) {
565 myBeforePnt = myPortIn->getConnectPnt();
568 myBeforePnt = myPortInES->getConnectPnt();
573 myEngine->Coords(myHltPnt-1, aX, aY);
574 myBeforePnt = myGraph->contentsToViewport(QPoint(aX, aY));
576 if (myHltPnt == myEngine->CoordsSize())
577 myAfterPnt = myPortOut->getConnectPnt();
580 myEngine->Coords(myHltPnt+1, aX, aY);
581 myAfterPnt = myGraph->contentsToViewport(QPoint(aX, aY));
584 myEngine->Coords(myHltPnt, aX, aY);
585 myMovedPnt = myGraph->contentsToViewport(QPoint(aX, aY));
587 myPainter = new QPainter(myGraph->viewport());
588 QPen aOldPen(myGraph->viewport()->paletteBackgroundColor(), LINE_WIDTH);
590 myPainter->setPen(aOldPen);
593 myPainter->setPen(myTmpPen);
594 myPainter->setRasterOp(Qt::XorROP);
597 myPntMovingState = true;
599 } else if (myHltPnt > -1)
603 //**********************************************************************
604 void SUPERVGUI_Link::onMouseRelease(QMouseEvent * theEvent){
605 if (theEvent->button() != Qt::LeftButton) return;
607 if (myPntMovingState) {
608 myPntMovingState = false;
609 LinkIsMoving = false;
614 int aX = (theEvent->pos().x() > 0)? theEvent->pos().x(): 1;
615 int aY = (theEvent->pos().y() > 0)? theEvent->pos().y(): 1;
616 aX = (aX < myGraph->contentsWidth())? aX: myGraph->contentsWidth()-1;
617 aY = (aY < myGraph->contentsHeight())? aY: myGraph->contentsHeight()-1;
618 myEngine->ChangeCoord(myHltPnt, aX, aY);
624 //**********************************************************************
626 * Connects to the Graph mouse events
628 void SUPERVGUI_Link::connectToEvents() {
629 connect(myGraph, SIGNAL(mouseMoved(QMouseEvent*)),
630 this, SLOT(onMouseMove(QMouseEvent*)));
632 connect(myGraph, SIGNAL(mousePressed(QMouseEvent*)),
633 this, SLOT(onMousePress(QMouseEvent*)));
635 connect(myGraph, SIGNAL(mouseReleased(QMouseEvent*)),
636 this, SLOT(onMouseRelease(QMouseEvent*)));
640 //**********************************************************************
641 bool SUPERVGUI_Link::isSelected(QPoint thePnt) {
642 if (myEngine->CoordsSize() == 0) {
643 if (!isESInputPort()) {
644 return (distance(thePnt, myGraph->viewportToContents(myPortOut->getConnectPnt()),
645 myGraph->viewportToContents(myPortIn->getConnectPnt())) <= 0);
648 return (distance(thePnt, myGraph->viewportToContents(myPortOut->getConnectPnt()),
649 myGraph->viewportToContents(myPortInES->getConnectPnt())) <= 0);
654 myEngine->Coords(1, aX, aY);
655 if (!isESInputPort()) {
656 if (distance(thePnt, myGraph->viewportToContents(myPortIn->getConnectPnt()),
657 QPoint(aX, aY)) <= 0) {
662 if (distance(thePnt, myGraph->viewportToContents(myPortInES->getConnectPnt()),
663 QPoint(aX, aY)) <= 0) {
670 for (i = 2; i <= myEngine->CoordsSize(); i++) {
671 myEngine->Coords(i, aNextX, aNextY);
672 if (distance(thePnt, QPoint(aX, aY),
673 QPoint(aNextX, aNextY)) <= 0) {
679 if (distance(thePnt, QPoint(aX, aY),
680 myGraph->viewportToContents(myPortOut->getConnectPnt())) <= 0) {
688 //**********************************************************************
690 * Returns true if at least one point is within the rect.
691 * Rect must be in contents coordinate space
693 bool SUPERVGUI_Link::isInRect(int theX, int theY, int theW, int theH) {
694 QRect aRect(theX, theY, theW, theH);
695 if (aRect.contains(myGraph->viewportToContents(myPortOut->getConnectPnt()), true))
698 if (!isESInputPort()) {
699 if (aRect.contains(myGraph->viewportToContents(myPortIn->getConnectPnt()), true)) {
704 if (aRect.contains(myGraph->viewportToContents(myPortInES->getConnectPnt()), true)) {
711 if (!isESInputPort())
712 aPrevPnt = myGraph->viewportToContents(myPortIn->getConnectPnt());
714 aPrevPnt = myGraph->viewportToContents(myPortInES->getConnectPnt());
715 for (int i = 1; i <= myEngine->CoordsSize(); i++) {
716 myEngine->Coords(i, aX, aY);
717 if (aRect.contains(aX, aY, true))
720 QRect aTmpRect(QPoint(QMIN(aPrevPnt.x(), aX),
721 QMIN(aPrevPnt.y(), aY)),
722 QPoint(QMAX(aPrevPnt.x(), aX),
723 QMAX(aPrevPnt.y(), aY)));
724 if (aRect.intersects(aTmpRect))
726 aPrevPnt = QPoint(aX, aY);
729 QPoint aLastPnt = myGraph->viewportToContents(myPortOut->getConnectPnt());
730 QRect aLastRect(QPoint(QMIN(aPrevPnt.x(), aLastPnt.x()),
731 QMIN(aPrevPnt.y(), aLastPnt.y())),
732 QPoint(QMAX(aPrevPnt.x(), aLastPnt.x()),
733 QMAX(aPrevPnt.y(), aLastPnt.y())));
734 if (aRect.intersects(aLastRect))
741 //**********************************************************************
743 * Calculates distance between points
745 int distance(int x1, int y1, int x2, int y2) {
750 return (int) sqrt((double)(x + y));
754 //**********************************************************************
756 * Finds distance between thePnt and line(thePntLn1, thePntLn2)
757 * Returned value is not an mathematical value - this is only estimation of
758 * of closing point to the line. 0 - means that point belongs to the line
760 int distance(QPoint thePnt, QPoint thePntLn1, QPoint thePntLn2) {
766 int lx = thePntLn1.x();
767 int ly = thePntLn1.y();
768 int nx = thePntLn2.x();
769 int ny = thePntLn2.y();
775 a = (int) sqrt((double)(r + s));
781 b = (int) sqrt((double)(r + s));
787 c = (int) sqrt((double)(r + s));
792 void SUPERVGUI_Link::setBeginPort(SUPERVGUI_Port* theBeginPort) {
793 myBeginPort = theBeginPort;
796 SUPERVGUI_Port* SUPERVGUI_Link::getBeginPort() {