1 // Copyright (C) 2006-2013 CEA/DEN, EDF 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
23 #include "SceneLinkItem.hxx"
24 #include "SceneDataPortItem.hxx"
25 #include "SceneCtrlPortItem.hxx"
26 #include "SceneElementaryNodeItem.hxx"
27 #include "SceneHeaderNodeItem.hxx"
29 #include "Resource.hxx"
36 #include "YacsTrace.hxx"
39 using namespace YACS::ENGINE;
40 using namespace YACS::HMI;
43 SceneLinkItem::SceneLinkItem(QGraphicsScene *scene, SceneItem *parent,
44 ScenePortItem* from, ScenePortItem* to,
45 QString label, Subject *subject)
46 : SceneObserverItem(scene, parent, label, subject)
50 _penColor = Resource::link_draw_color.darker(Resource::link_pen_darkness);
51 _hiPenColor = Resource::link_select_color.darker(Resource::link_pen_darkness);
52 _brushColor = Resource::link_draw_color;
53 _hiBrushColor = Resource::link_select_color;
56 DEBTRACE("ZValue=" << zValue());
60 _path = QPainterPath();
63 SceneLinkItem::~SceneLinkItem()
67 void SceneLinkItem::select(bool isSelected)
70 setZValue(_level+100);
73 DEBTRACE("ZValue=" << zValue());
74 SceneObserverItem::select(isSelected);
77 QRectF SceneLinkItem::boundingRect() const
79 return _path.boundingRect();
82 QPainterPath SceneLinkItem::shape() const
84 //DEBTRACE("SceneLinkItem::shape");
88 void SceneLinkItem::setShape(int thickness)
91 _path = QPainterPath();
92 _path.setFillRule(Qt::WindingFill);
93 QPointF pfrom = start();
95 DEBTRACE(Scene::_straightLinks);
96 if (_nbPoints && !Scene::_straightLinks)
99 addArrow(pfrom, _lp[0], _RIGHT, thickness);
100 for (int k=0; k<_nbPoints-1; k++)
101 addArrow(_lp[k], _lp[k+1], _directions[k+1], thickness);
102 addArrow(_lp[_nbPoints-1], pto, _RIGHT, thickness);
107 double d = std::sqrt((pto.x() - pfrom.x())*(pto.x() - pfrom.x()) + (pto.y() - pfrom.y())*(pto.y() - pfrom.y()));
108 double sina = (pto.y() - pfrom.y())/d;
109 double cosa = (pto.x() - pfrom.x())/d;
110 double ep=3.0*thickness/2.0 * Resource::link_thickness;
111 _path.moveTo(pfrom.x() -ep*sina, pfrom.y() +ep*cosa);
112 _path.lineTo(pto.x() -ep*sina, pto.y() +ep*cosa);
113 _path.lineTo(pto.x() +ep*sina, pto.y() -ep*cosa);
114 _path.lineTo(pfrom.x() +ep*sina, pfrom.y() -ep*cosa);
115 _path.lineTo(pfrom.x() -ep*sina, pfrom.y() -ep*cosa);
117 double x=(pto.x() + pfrom.x())/2.;
118 double y=(pto.y() + pfrom.y())/2.;
121 _path.moveTo(x+l*cosa,y+l*sina);
122 _path.lineTo(x+e*sina,y-e*cosa);
123 _path.lineTo(x-e*sina,y+e*cosa);
124 _path.lineTo(x+l*cosa,y+l*sina);
128 void SceneLinkItem::addArrow(QPointF pfrom,
130 YACS::HMI::Direction dir,
133 qreal x, y, width, height, length;
134 double ep=thickness * Resource::link_thickness;
141 height = 2*ep + pto.y() -pfrom.y();
147 width = 2*ep + pto.x() -pfrom.x();
155 height = 2*ep + pfrom.y() -pto.y();
161 width = 2*ep + pfrom.x() -pto.x();
166 _path.addRect(x, y, width, height);
170 int e=5*ep, h1=4*ep, h2=8*ep;
175 y = (pto.y() + pfrom.y())/2 +h1;
177 _path.lineTo(x+e, y-h2);
178 _path.lineTo(x, y-h1);
179 _path.lineTo(x-e, y-h2);
183 x = (pto.x() + pfrom.x())/2 +h1;
186 _path.lineTo(x-h2, y+e);
187 _path.lineTo(x-h1, y );
188 _path.lineTo(x-h2, y-e);
193 y = (pto.y() + pfrom.y())/2 -h1;
195 _path.lineTo(x+e, y+h2);
196 _path.lineTo(x, y+h1);
197 _path.lineTo(x-e, y+h2);
201 x = (pto.x() + pfrom.x())/2 -h1;
204 _path.lineTo(x+h2, y+e);
205 _path.lineTo(x+h1, y );
206 _path.lineTo(x+h2, y-e);
213 void SceneLinkItem::paint(QPainter *painter,
214 const QStyleOptionGraphicsItem *option,
217 //DEBTRACE("SceneLinkItem::paint " << _label.toStdString());
218 if (_path.isEmpty()) setShape(_emphasized+1);
221 pen.setColor(getPenColor());
222 painter->setPen(pen);
223 painter->setBrush(getBrushColor());
224 painter->drawPath(_path);
228 void SceneLinkItem::update(GuiEvent event, int type, Subject* son)
230 DEBTRACE("SceneLinkItem::update "<< eventName(event)<<" "<<type<<" "<<son);
233 case YACS::HMI::EMPHASIZE:
234 DEBTRACE("SceneObserverItem::update EMPHASIZE " << type);
238 setZValue(_level+100);
239 DEBTRACE("ZValue=" << zValue());
246 DEBTRACE("ZValue=" << zValue());
249 QGraphicsItem::update();
251 case YACS::HMI::SWITCHSHAPE:
252 DEBTRACE("SceneObserverItem::update SWITCHSHAPE");
253 setShape(_emphasized+1);
254 QGraphicsItem::update();
261 void SceneLinkItem::popupMenu(QWidget *caller, const QPoint &globalPos)
264 m.popupMenu(caller, globalPos);
267 void SceneLinkItem::setPath(LinkPath lp)
269 DEBTRACE("SceneLinkItem::setPath " << lp.size());
271 prepareGeometryChange();
272 _nbPoints = lp.size();
273 _lp.reserve(_nbPoints+1);
274 _directions.reserve(_nbPoints +2);
275 std::list<linkPoint>::const_iterator it = lp.begin();
281 for (; it != lp.end(); ++it)
283 QPointF p = mapFromScene(QPointF((*it).x, (*it).y));
284 DEBTRACE("p(" << p.x() << "," << p.y() << ")");
288 _lp[k].setY(start().y());
289 _directions[k] = _RIGHT; // --- direction from start to point k=0
294 bool changeDir = true;
295 if (dirx && (p.y() == prevy))
297 _lp[k-1].setX(p.x());
300 if (diry && (p.x() == prevx))
302 _lp[k-1].setY(p.y());
310 if (p.x() > prevx) _directions[k] = _RIGHT; // --- direction from k-1 to k
311 else if (p.x() < prevx) _directions[k] = _LEFT;
312 else if (p.y() > prevy) _directions[k] = _UP;
313 else if (p.y() < prevy) _directions[k] = _DOWN;
323 //link should be direct (k=0) or orthogonal k>=2
326 _lp[1].setY(goal().y());
327 if (goal().y() > start().y()) _directions[1] = _UP;
328 else _directions[1] = _DOWN;
331 if(k>2 && _directions[k-1]==_RIGHT)
338 _lp[k-1].setY(goal().y());
339 _directions[k] = _RIGHT; // --- direction from point k-1 to goal
342 for (k = _nbPoints -2; k >= 0; k--)
344 if(_lp[k].y() == prevy)
345 _lp[k].setY(goal().y());
351 if (Scene::_simplifyLinks) minimizeDirectionChanges();
354 if (Scene::_force2NodesLink) force2points();
355 for (k=0; k<_nbPoints; k++)
356 DEBTRACE("_lp[" << k << "](" << _lp[k].x() << "," << _lp[k].y() << ")");
357 setShape(_emphasized+1);
362 * replace patterns like (right, down, right, down) with (right, right, down, down)
363 * if new path is OK (no obstacle in the modified rectangle), then combine the segments.
365 void SceneLinkItem::minimizeDirectionChanges()
367 vector<QPointF> newlp;
368 vector<Direction> newdir;
369 newlp.reserve(_nbPoints);
370 newdir.reserve(_nbPoints +1);
372 bool modified = true;
376 Direction prevdir = _RIGHT;
378 newdir[0] = _directions[0];
380 for (int k = 0; k < _nbPoints; k++)
382 if (k< _nbPoints-2) // --- _nbPoints + 1 directions, look to k+3
383 if ((_directions[k] == _directions[k+2]) && (_directions[k+1] == _directions[k+3]))
388 if ((_directions[k] == _RIGHT) || (_directions[k] == _LEFT))
399 qreal xtop, ytop, width, height;
400 if (_lp[k].x() < _lp[k+2].x())
403 width = _lp[k+2].x() - _lp[k].x();
408 width = _lp[k].x() - _lp[k+2].x();
410 if (_lp[k].y() < _lp[k+2].y())
413 height = _lp[k+2].y() - _lp[k].y();
418 height = _lp[k].y() - _lp[k+2].y();
420 QRectF aRect(mapToScene(QPointF(xtop, ytop)),
421 mapToScene(QPointF(xtop + width, ytop + height)));
422 QList<QGraphicsItem*> itemList = scene()->items(aRect);
423 for (int kk=0; kk<itemList.size(); kk++)
425 QGraphicsItem *item = itemList[kk];
426 if ((dynamic_cast<SceneElementaryNodeItem*>(item)) ||
427 (dynamic_cast<SceneHeaderNodeItem*>(item)))
436 _lp[k+1] = QPointF(tryx, tryy);
437 _directions[k+1] = _directions[k];
438 _directions[k+2] = _directions[k+3];
443 if (prevdir == _directions[k])
445 if ((prevdir == _RIGHT) || (prevdir == _LEFT))
446 newlp[newk].setX(_lp[k].x());
448 newlp[newk].setY(_lp[k].y());
453 newlp[newk] = _lp[k];
454 newdir[newk] = _directions[k];
458 prevdir = _directions[k];
460 DEBTRACE("modified : _nbPoints=" << _nbPoints << " newk=" << newk+1);
463 // for (int i=0; i<=newk; i++)
465 // DEBTRACE("("<< _lp[i].x() << "," << _lp[i].y() << ") ("
466 // << newlp[i].x() << "," << newlp[i].y() << ") "
467 // << _directions[i] << "-" << newdir[i]);
469 // for (int i=newk+1; i<_nbPoints; i++)
471 // DEBTRACE("("<< _lp[i].x() << "," << _lp[i].y() << ") "
472 // << _directions[i]);
475 if(newdir[newk]==_RIGHT)
481 for (int i=0; i<_nbPoints; i++)
484 _directions[i] = newdir[i];
486 _directions[_nbPoints] = _RIGHT;
487 DEBTRACE("_nbPoints " << _nbPoints);
492 void SceneLinkItem::force2points()
500 vector<QPointF> newlp;
501 vector<Direction> newdir;
502 newlp.reserve(_nbPoints+1);
503 newdir.reserve(_nbPoints +2);
504 //_lp.reserve(_nbPoints +1); // --- not OK : data may be lost! pre reserve enough before!
505 //_directions.reserve(_nbPoints +2);
508 newlp[0].setY(a.y());
509 newlp[1].setY(b.y());
517 for (int i=0; i<_nbPoints; i++)
520 _directions[i] = newdir[i];
522 _directions[_nbPoints] = _RIGHT;
528 QPointF SceneLinkItem::start()
530 SceneDataPortItem* dpif = dynamic_cast<SceneDataPortItem*>(_from);
531 QPointF localFrom(dpif->getWidth()*(9.5/10), dpif->getHeight()/2);
532 DEBTRACE("localFrom(" << localFrom.x() << "," << localFrom.y() << ")");
533 return mapFromItem(dpif, localFrom);
536 QPointF SceneLinkItem::goal()
538 SceneDataPortItem* dpit = dynamic_cast<SceneDataPortItem*>(_to);
539 QPointF localTo(dpit->getWidth()/20, dpit->getHeight()/2);
540 DEBTRACE("localTo(" << localTo.x() << "," << localTo.y() << ")");
541 return mapFromItem(dpit, localTo);
544 void SceneLinkItem::updateShape()
546 prepareGeometryChange();
549 // a path has been calculated, update it
550 QPointF pfrom = start();
551 QPointF pto = goal();
552 _lp[0].setY(pfrom.y());
553 if(_lp[1].y() > _lp[0].y())_directions[1]=_UP;
554 else _directions[1]=_DOWN;
555 _lp[_nbPoints-1].setY(pto.y());
556 if(_lp[_nbPoints-1].y() > _lp[_nbPoints-2].y())_directions[_nbPoints-1]=_UP;
557 else _directions[_nbPoints-1]=_DOWN;
559 setShape(_emphasized+1);
562 QColor SceneLinkItem::getPenColor()
564 _penColor = Resource::link_draw_color.darker(Resource::link_pen_darkness);
565 _hiPenColor = Resource::link_select_color.darker(Resource::link_pen_darkness);
566 return SceneObserverItem::getPenColor();
569 QColor SceneLinkItem::getBrushColor()
571 _brushColor = Resource::link_draw_color;
572 _hiBrushColor = Resource::link_select_color;
573 return SceneObserverItem::getBrushColor();
576 // Get the node at the "from" place of the link
577 SceneNodeItem* SceneLinkItem::getFromNode() {
578 SceneCtrlPortItem* p = dynamic_cast<SceneCtrlPortItem*>(_from);
580 return(p->getParentNode());
586 // Get the node at the "to" place of the link
587 SceneNodeItem* SceneLinkItem::getToNode() {
588 SceneCtrlPortItem* p = dynamic_cast<SceneCtrlPortItem*>(_to);
590 return(p->getParentNode());