Version: 9.16.0
SceneLinkItem.cxx
Go to the documentation of this file.
1// Copyright (C) 2006-2026 CEA, EDF
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, or (at your option) any later version.
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#define CHRONODEF
21#include "chrono.hxx"
22
23#include "SceneLinkItem.hxx"
24#include "SceneDataPortItem.hxx"
25#include "SceneCtrlPortItem.hxx"
28#include "Scene.hxx"
29#include "Resource.hxx"
30
31#include "Menus.hxx"
32#include <QPointF>
33#include <cmath>
34
35//#define _DEVDEBUG_
36#include "YacsTrace.hxx"
37
38using namespace std;
39using namespace YACS::ENGINE;
40using namespace YACS::HMI;
41
42
43SceneLinkItem::SceneLinkItem(QGraphicsScene *scene, SceneItem *parent,
45 QString label, Subject *subject)
46 : SceneObserverItem(scene, parent, label, subject)
47{
48 _from = from;
49 _to = to;
54 _level += 100;
55 setZValue(_level);
56 DEBTRACE("ZValue=" << zValue());
57 _lp.clear();
58 _directions.clear();
59 _nbPoints = 0;
60 _path = QPainterPath();
61}
62
64{
65}
66
67void SceneLinkItem::select(bool isSelected)
68{
69 if (isSelected)
70 setZValue(_level+100);
71 else
72 setZValue(_level);
73 DEBTRACE("ZValue=" << zValue());
74 SceneObserverItem::select(isSelected);
75}
76
78{
79 return _path.boundingRect();
80}
81
82QPainterPath SceneLinkItem::shape() const
83{
84 //DEBTRACE("SceneLinkItem::shape");
85 return _path;
86}
87
88void SceneLinkItem::setShape(int thickness)
89{
90 DEBTRACE("---");
91 _path = QPainterPath();
92 _path.setFillRule(Qt::WindingFill);
93 QPointF pfrom = start();
94 QPointF pto = goal();
97 {
98 DEBTRACE("---");
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);
103 }
104 else
105 {
106 DEBTRACE("---");
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);
116 //arrow
117 double x=(pto.x() + pfrom.x())/2.;
118 double y=(pto.y() + pfrom.y())/2.;
119 double l=8*ep;
120 double e=4*ep;
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);
125 }
126}
127
128void SceneLinkItem::addArrow(QPointF pfrom,
129 QPointF pto,
131 int thickness)
132{
133 qreal x, y, width, height, length;
134 double ep=thickness * Resource::link_thickness;
135 switch (dir)
136 {
137 case _UP:
138 x = pfrom.x() -ep;
139 y = pfrom.y() -ep;
140 width = 3*ep;
141 height = 2*ep + pto.y() -pfrom.y();
142 length = height;
143 break;
144 case _RIGHT:
145 x = pfrom.x() -ep;
146 y = pfrom.y() -ep;
147 width = 2*ep + pto.x() -pfrom.x();
148 height = 3*ep;
149 length = width;
150 break;
151 case _DOWN:
152 x = pto.x() -ep;
153 y = pto.y() -ep;
154 width = 3*ep;
155 height = 2*ep + pfrom.y() -pto.y();
156 length = height;
157 break;
158 case _LEFT:
159 x = pto.x() -ep;
160 y = pto.y() -ep;
161 width = 2*ep + pfrom.x() -pto.x();
162 height = 3*ep;
163 length = width;
164 break;
165 }
166 _path.addRect(x, y, width, height);
167
168 if (length > 20)
169 {
170 int e=5*ep, h1=4*ep, h2=8*ep;
171 switch (dir)
172 {
173 case _UP:
174 x = pfrom.x();
175 y = (pto.y() + pfrom.y())/2 +h1;
176 _path.moveTo(x, y);
177 _path.lineTo(x+e, y-h2);
178 _path.lineTo(x, y-h1);
179 _path.lineTo(x-e, y-h2);
180 _path.lineTo(x, y );
181 break;
182 case _RIGHT:
183 x = (pto.x() + pfrom.x())/2 +h1;
184 y = pfrom.y();
185 _path.moveTo(x, y);
186 _path.lineTo(x-h2, y+e);
187 _path.lineTo(x-h1, y );
188 _path.lineTo(x-h2, y-e);
189 _path.lineTo(x, y );
190 break;
191 case _DOWN:
192 x = pfrom.x();
193 y = (pto.y() + pfrom.y())/2 -h1;
194 _path.moveTo(x, y);
195 _path.lineTo(x+e, y+h2);
196 _path.lineTo(x, y+h1);
197 _path.lineTo(x-e, y+h2);
198 _path.lineTo(x, y );
199 break;
200 case _LEFT:
201 x = (pto.x() + pfrom.x())/2 -h1;
202 y = pfrom.y();
203 _path.moveTo(x, y);
204 _path.lineTo(x+h2, y+e);
205 _path.lineTo(x+h1, y );
206 _path.lineTo(x+h2, y-e);
207 _path.lineTo(x, y );
208 break;
209 }
210 }
211}
212
213void SceneLinkItem::paint(QPainter *painter,
214 const QStyleOptionGraphicsItem *option,
215 QWidget *widget)
216{
217 //DEBTRACE("SceneLinkItem::paint " << _label.toStdString());
218 if (_path.isEmpty()) setShape(_emphasized+1);
219 painter->save();
220 QPen pen;
221 pen.setColor(getPenColor());
222 painter->setPen(pen);
223 painter->setBrush(getBrushColor());
224 painter->drawPath(_path);
225 painter->restore();
226}
227
228void SceneLinkItem::update(GuiEvent event, int type, Subject* son)
229{
230 DEBTRACE("SceneLinkItem::update "<< eventName(event)<<" "<<type<<" "<<son);
231 switch (event)
232 {
234 DEBTRACE("SceneObserverItem::update EMPHASIZE " << type);
235 if (type)
236 {
237 _emphasized = true;
238 setZValue(_level+100);
239 DEBTRACE("ZValue=" << zValue());
240 setShape(2);
241 }
242 else
243 {
244 _emphasized = false;
245 setZValue(_level);
246 DEBTRACE("ZValue=" << zValue());
247 setShape();
248 }
249 QGraphicsItem::update();
250 break;
252 DEBTRACE("SceneObserverItem::update SWITCHSHAPE");
254 QGraphicsItem::update();
255 break;
256 default:
257 ;
258 }
259}
260
261void SceneLinkItem::popupMenu(QWidget *caller, const QPoint &globalPos)
262{
263 LinkMenu m;
264 m.popupMenu(caller, globalPos);
265}
266
268{
269 DEBTRACE("SceneLinkItem::setPath " << lp.size());
270 CHRONO(10);
271 prepareGeometryChange();
272 _nbPoints = lp.size();
273 _lp.resize(_nbPoints+1);
274 _directions.resize(_nbPoints +2);
275 std::list<linkPoint>::const_iterator it = lp.begin();
276 int k=0;
277 qreal prevx = 0;
278 qreal prevy = 0;
279 bool dirx = true;
280 bool diry = false;
281 for (; it != lp.end(); ++it)
282 {
283 QPointF p = mapFromScene(QPointF((*it).x, (*it).y));
284 DEBTRACE("p(" << p.x() << "," << p.y() << ")");
285 if (k == 0)
286 {
287 _lp[k] = p;
288 _lp[k].setY(start().y());
289 _directions[k] = _RIGHT; // --- direction from start to point k=0
290 k++;
291 }
292 else
293 {
294 bool changeDir = true;
295 if (dirx && (p.y() == prevy))
296 {
297 _lp[k-1].setX(p.x());
298 changeDir = false;
299 }
300 if (diry && (p.x() == prevx))
301 {
302 _lp[k-1].setY(p.y());
303 changeDir = false;
304 }
305 if (changeDir)
306 {
307 dirx = !dirx;
308 diry = !diry;
309 _lp[k] = p;
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;
314 k++;
315 }
316 }
317 prevx = p.x();
318 prevy = p.y();
319 }
320
321 if(k==1)
322 {
323 //link should be direct (k=0) or orthogonal k>=2
324 k=2;
325 _lp[1]=_lp[0];
326 _lp[1].setY(goal().y());
327 if (goal().y() > start().y()) _directions[1] = _UP;
328 else _directions[1] = _DOWN;
329 }
330
331 if(k>2 && _directions[k-1]==_RIGHT)
332 {
333 //remove last point
334 k=k-1;
335 }
336
337 _nbPoints = k;
338 _lp[k-1].setY(goal().y());
339 _directions[k] = _RIGHT; // --- direction from point k-1 to goal
340 dirx = true;
341 diry = false;
342 for (k = _nbPoints -2; k >= 0; k--)
343 {
344 if(_lp[k].y() == prevy)
345 _lp[k].setY(goal().y());
346 else
347 break;
348 }
349 CHRONOSTOP(10);
350 CHRONO(11);
352 CHRONOSTOP(11);
353 CHRONO(12);
355 for (k=0; k<_nbPoints; k++)
356 DEBTRACE("_lp[" << k << "](" << _lp[k].x() << "," << _lp[k].y() << ")");
358 SceneItem::update();
359}
360
366{
367 vector<QPointF> newlp;
368 vector<Direction> newdir;
369 newlp.resize(_nbPoints);
370 newdir.resize(_nbPoints +1);
371
372 bool modified = true;
373 while (modified)
374 {
375 modified = false;
376 Direction prevdir = _RIGHT;
377 newlp[0] = _lp[0];
378 newdir[0] = _directions[0];
379 int newk = 0;
380 for (int k = 0; k < _nbPoints; k++)
381 {
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]))
384 {
385 bool kmodif = true;
386 qreal tryx;
387 qreal tryy;
388 if ((_directions[k] == _RIGHT) || (_directions[k] == _LEFT))
389 {
390 tryy = _lp[k].y();
391 tryx = _lp[k+2].x();
392 }
393 else
394 {
395 tryy = _lp[k+2].y();
396 tryx = _lp[k].x();
397 }
398
399 qreal xtop, ytop, width, height;
400 if (_lp[k].x() < _lp[k+2].x())
401 {
402 xtop = _lp[k].x();
403 width = _lp[k+2].x() - _lp[k].x();
404 }
405 else
406 {
407 xtop = _lp[k+2].x();
408 width = _lp[k].x() - _lp[k+2].x();
409 }
410 if (_lp[k].y() < _lp[k+2].y())
411 {
412 ytop = _lp[k].y();
413 height = _lp[k+2].y() - _lp[k].y();
414 }
415 else
416 {
417 ytop = _lp[k+2].y();
418 height = _lp[k].y() - _lp[k+2].y();
419 }
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++)
424 {
425 QGraphicsItem *item = itemList[kk];
426 if ((dynamic_cast<SceneElementaryNodeItem*>(item)) ||
427 (dynamic_cast<SceneHeaderNodeItem*>(item)))
428 {
429 kmodif = false;
430 break;
431 }}
432
433 if (kmodif)
434 {
435 modified = true;
436 _lp[k+1] = QPointF(tryx, tryy);
437 _directions[k+1] = _directions[k];
438 _directions[k+2] = _directions[k+3];
439 }
440 }
441 if (k>0)
442 {
443 if (prevdir == _directions[k])
444 {
445 if ((prevdir == _RIGHT) || (prevdir == _LEFT))
446 newlp[newk].setX(_lp[k].x());
447 else
448 newlp[newk].setY(_lp[k].y());
449 }
450 else
451 {
452 newk++;
453 newlp[newk] = _lp[k];
454 newdir[newk] = _directions[k];
455 }
456
457 }
458 prevdir = _directions[k];
459 }
460 DEBTRACE("modified : _nbPoints=" << _nbPoints << " newk=" << newk+1);
461 if (modified)
462 {
463// for (int i=0; i<=newk; i++)
464// {
465// DEBTRACE("("<< _lp[i].x() << "," << _lp[i].y() << ") ("
466// << newlp[i].x() << "," << newlp[i].y() << ") "
467// << _directions[i] << "-" << newdir[i]);
468// }
469// for (int i=newk+1; i<_nbPoints; i++)
470// {
471// DEBTRACE("("<< _lp[i].x() << "," << _lp[i].y() << ") "
472// << _directions[i]);
473// }
474
475 if(newdir[newk]==_RIGHT)
476 {
477 //remove last point
478 newk=newk-1;
479 }
480 _nbPoints = newk+1;
481 for (int i=0; i<_nbPoints; i++)
482 {
483 _lp[i] = newlp[i];
484 _directions[i] = newdir[i];
485 }
487 DEBTRACE("_nbPoints " << _nbPoints);
488 }
489 }
490}
491
493{
494 if (_nbPoints == 1)
495 {
496 QPointF a = start();
497 QPointF b = goal();
498 if (a.y() != b.y())
499 {
500 vector<QPointF> newlp;
501 vector<Direction> newdir;
502 newlp.resize(_nbPoints+1);
503 newdir.resize(_nbPoints +2);
504 //_lp.resize(_nbPoints +1); // --- not OK : data may be lost! pre reserve enough before!
505 //_directions.resize(_nbPoints +2);
506 newlp[0] = _lp[0];
507 newlp[1] = _lp[0];
508 newlp[0].setY(a.y());
509 newlp[1].setY(b.y());
510 newdir[0] = _RIGHT;
511 newdir[2] = _RIGHT;
512 if (a.y() > b.y())
513 newdir[1] = _DOWN;
514 else
515 newdir[1] = _UP;
516 _nbPoints = 2;
517 for (int i=0; i<_nbPoints; i++)
518 {
519 _lp[i] = newlp[i];
520 _directions[i] = newdir[i];
521 }
523 }
524 }
525}
526
527
529{
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);
534}
535
537{
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);
542}
543
545{
546 prepareGeometryChange();
547 if (_nbPoints)
548 {
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;
558 }
560}
561
563{
567}
568
570{
574}
575
576// Get the node at the "from" place of the link
578 SceneCtrlPortItem* p = dynamic_cast<SceneCtrlPortItem*>(_from);
579 if (p) {
580 return(p->getParentNode());
581 } else {
582 return(NULL);
583 };
584}
585
586// Get the node at the "to" place of the link
588 SceneCtrlPortItem* p = dynamic_cast<SceneCtrlPortItem*>(_to);
589 if (p) {
590 return(p->getParentNode());
591 } else {
592 return(NULL);
593 };
594}
#define DEBTRACE(msg)
Definition: YacsTrace.hxx:31
#define CHRONO(i)
Definition: chrono.hxx:88
#define CHRONOSTOP(i)
Definition: chrono.hxx:89
static std::string eventName(GuiEvent event)
static int link_pen_darkness
Definition: Resource.hxx:266
static QColor link_draw_color
Definition: Resource.hxx:259
static double link_thickness
Definition: Resource.hxx:268
static QColor link_select_color
Definition: Resource.hxx:261
virtual QColor getPenColor()
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
virtual SceneNodeItem * getToNode()
void setShape(int thickness=1)
std::vector< QPointF > _lp
virtual void popupMenu(QWidget *caller, const QPoint &globalPos)
std::vector< Direction > _directions
virtual QPainterPath shape() const
virtual SceneNodeItem * getFromNode()
virtual QPointF goal()
virtual void minimizeDirectionChanges()
void addArrow(QPointF pfrom, QPointF pto, HMI::Direction dir, int thickness=1)
virtual void select(bool isSelected)
virtual void update(GuiEvent event, int type, Subject *son)
virtual QRectF boundingRect() const
virtual QPointF start()
virtual QColor getPenColor()
virtual void setPath(LinkPath lp)
virtual QColor getBrushColor()
virtual void select(bool isSelected)
static bool _simplifyLinks
Definition: Scene.hxx:38
static bool _straightLinks
Definition: Scene.hxx:36
static bool _force2NodesLink
Definition: Scene.hxx:39
Proc * p
Definition: driver.cxx:216
std::list< linkPoint > LinkPath
Definition: LinkMatrix.hxx:77