TransitionItem.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package
19  * @author
20  * @date
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 #include "TransitionItem.h"
25 
26 #include <cmath>
27 #include <memory>
28 
29 #include <QGraphicsScene>
30 #include <QGraphicsSceneMouseEvent>
31 #include <QGraphicsView>
32 #include <QMenu>
33 #include <QPainter>
34 #include <QPen>
35 #include <QPropertyAnimation>
36 #include <QStyleOptionGraphicsItem>
37 
39 
41 
42 #include "../model/Transition.h"
43 #include "../model/stateinstance/StateInstance.h"
44 #include "SplinePath.h"
45 #include "StateItem.h"
46 
47 
48 #define INITIAL_CIRCLE_RADIUS 10
49 
50 namespace armarx
51 {
52 
54  QGraphicsItem* parent) :
55  QGraphicsPathItem(parent),
56  MorphingItem(this),
57  transition(transition),
58  transitionLabel(NULL),
59  pointAttachedToMouse(-1),
60  highlightColor(255, 0, 0),
61  normalColor(Qt::black),
62  animation(this, "color")
63  {
64  setCacheMode(DeviceCoordinateCache);
65  color = Qt::black;
66  setPen(QPen(color, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
67  setBrush(Qt::Dense3Pattern);
68  setFlag(QGraphicsItem::ItemIsSelectable, true);
69  setAcceptHoverEvents(true);
70  if (transition)
71  {
72  transitionLabel = new TransitionLabel("", this);
73 
74  transitionLabel->setZValue(100000);
75  updateLabel();
76  }
77  setZValue(100000);
78  }
79 
82  {
83  return highlightAnimationStartTime;
84  }
85 
86  QPainterPath
88  {
89 
90  QPainterPath path;
91 
92  if (isInitialTransition())
93  {
94  path.addEllipse(initialStateCircle);
95  }
96 
97  path.addPolygon(shapePolygon);
98  path.setFillRule(Qt::WindingFill);
99  return path;
100  }
101 
102  QRectF
104  {
105 
106 
107  if (isInitialTransition())
108  {
109  return QGraphicsPathItem::boundingRect().adjusted(
110  -2 - INITIAL_CIRCLE_RADIUS, -2 - INITIAL_CIRCLE_RADIUS, 2, 2) |
111  arrowHead.boundingRect();
112  }
113  else
114  {
115  return QGraphicsPathItem::boundingRect().adjusted(-2, -2, 2, 2) |
116  arrowHead.boundingRect();
117  }
118  }
119 
120  bool
122  {
123  if (transition && !transition->sourceState)
124  {
125  return true;
126  }
127 
128  return false;
129  }
130 
131  void
133  {
134  // TODO
135  }
136 
137  void
139  {
140  ARMARX_CHECK_EXPRESSION(transition != NULL);
141 
142  pointAttachedToMouse = -1;
143  SupportPoints points = transition->supportPoints;
144  // ARMARX_DEBUG << points.controlPoints.size() << " points at start";
145  //adapt the first point
146  if (transition->sourceState)
147  {
148  if (points.startPoint)
149  {
150  points.startPoint = std::make_shared<QPointF>(
151  calcIntersection(transition->sourceState, *(points.startPoint)));
152  }
153  else if (points.controlPoints.size() > 1)
154  {
155  //points.startPoint = std::make_shared<QPointF>(calcIntersection(transition->sourceState, points.controlPoints.first()));
156  points.controlPoints.replace(
157  0, calcIntersection(transition->sourceState, points.controlPoints.first()));
158  }
159  else if (points.controlPoints.size() == 1)
160  {
161  // ARMARX_DEBUG << "setting startpoint straight between sourceState and sfirst controlpoint";
162  points.startPoint = std::make_shared<QPointF>(
163  calcIntersection(transition->sourceState, points.controlPoints.first()));
164  //points.controlPoints.replace(0, calcIntersection(transition->sourceState, points.controlPoints.first()));
165  }
166  else if (
167  transition
168  ->destinationState) // calc start point so that it lies on the edge of the source state
169  {
170  // ARMARX_DEBUG << "adding controlpoint straight between dest state and source on edge of source";
171  points.startPoint = std::make_shared<QPointF>(calcIntersection(
172  transition->sourceState, transition->destinationState->getBounds().center()));
173  //points.controlPoints.push_front(calcIntersection(transition->sourceState, transition->destinationState->getBounds().center()));
174  }
175  else if (points.endPoint)
176  {
177  points.startPoint = std::make_shared<QPointF>(
178  calcIntersection(transition->sourceState, *points.endPoint));
179  // points.controlPoints.push_front(calcIntersection(transition->sourceState, *points.endPoint));
180  }
181  }
182  else
183  {
184  // this is the start transition
185  // if(transition->destinationState)
186  // points.controlPoints.push_back(transition->destinationState->getBounds().center());
187  if (points.controlPoints.size() == 0)
188  {
189  points.controlPoints.push_back(QPointF(50, 80));
190  }
191  assert(!(points.startPoint));
192  }
193 
194  //adapt the last point
195  if (transition->destinationState)
196  {
197  if (points.endPoint)
198  {
199  ARMARX_DEBUG << "Adjusting start point";
200  points.endPoint = std::make_shared<QPointF>(
201  calcIntersection(transition->destinationState, *(points.endPoint)));
202  }
203  else if (points.controlPoints.size() > 2)
204  {
205  ARMARX_DEBUG << "Adjusting first control point";
206  //replace the last control point
207  points.controlPoints.replace(
208  points.controlPoints.size() - 1,
209  calcIntersection(transition->destinationState, points.controlPoints.last()));
210  }
211  else if (points.controlPoints.size() >= 1)
212  {
214  << "inserting control point between last controlpoint and destination state";
215  points.controlPoints.push_back(
216  calcIntersection(transition->destinationState, points.controlPoints.last()));
217  }
218  else if (points.startPoint)
219  {
220  ARMARX_DEBUG << "inserting control point between startPoint and destination state";
221  points.controlPoints.push_back(
222  calcIntersection(transition->destinationState, *points.startPoint));
223  }
224  }
225  else
226  {
227  //this is a detached transition
228  //just keep control points as they were calculated otherwhere
229  }
230 
231  // Not working - why?
232  // if(transition->sourceState && points.controlPoints.size() > 1)
233  // {
234  // points.controlPoints.replace(0, calcIntersection(transition->sourceState, points.controlPoints.first()));
235  // }
236 
237  //calculate path using the spline class
238  auto pointList = points.toPointList();
239  if (pointList.size() <= 1)
240  {
241  //this is the start transition in the initial creation
242  pointList.push_front(QPointF(100, 400));
243  }
244  QPainterPath path = SplinePath::simplePath(pointList);
245  //TODO: simplePath geht davon aus, dass immer 2 oder n = 1 mod 3 Kontrollpunkte gegeben sind.
246  // Ist das immer gegeben?
247 
248 
249  if (isInitialTransition() && path.elementCount() > 0)
250  {
251  // draw initial start circle
252  int r = 10;
253  initialStateCircle.setTopLeft(
254  QPointF(path.elementAt(0).x - r, path.elementAt(0).y - r));
255  initialStateCircle.setWidth(r * 2);
256  initialStateCircle.setHeight(r * 2);
257  }
258 
259  setPath(path);
260  recalcLabelPose();
261 
262  recalcShape();
263  }
264 
265  void
267  {
269  }
270 
271  void
273  {
274  QGraphicsItem::setSelected(selected);
275  }
276 
277  void
278  TransitionItem::attachToMouse(int supportPointIndex)
279  {
280  pointAttachedToMouse = supportPointIndex;
281  }
282 
283  void
285  {
286  animation.stop();
287  highlightAnimationStartTime = IceUtil::Time::now();
288  animation.setDuration(duration);
289  animation.setKeyValueAt(0, highlightColor);
290  // animation.setKeyValueAt(0.3, normalColor);
291  // animation.setKeyValueAt(0.99, QColor(255, 0, 0));
292  animation.setKeyValueAt(1, normalColor);
293 
294  animation.setEasingCurve(QEasingCurve::InOutQuad);
295  animation.start();
296  }
297 
298  void
300  {
301  if (transitionLabel)
302  {
303  auto labelText = transition->eventName + (transition->transitionUserCode ? " (C)" : "");
304  transitionLabel->setText(labelText);
305  transitionLabel->update();
306  QString eventName = transition->eventName;
307  if (!transition->sourceState)
308  {
309  eventName = "Initial Transition";
310  }
311  setToolTip("Event: " + eventName + " - " +
312  (transition->transitionUserCode ? "Transition with user code"
313  : "Transition without user code"));
314  }
315  }
316 
317  QPolygonF
318  TransitionItem::calcHull(QPainter* painter) const
319  {
320  auto path = this->path();
321  QPolygonF hull;
322 
323  auto addHull = [&](bool forward, float width)
324  {
325  float step = 0.0499999;
326  float start = 0;
327  float end = 1;
328  float offsetAngle = M_PI / 2;
329 
330  if (!forward)
331  {
332  offsetAngle = -M_PI / 2;
333  }
334 
335  QPointF p2;
336 
337  if (path.length() == 0)
338  {
339  return;
340  }
341 
342  for (float percent = start; percent <= end; percent += step)
343  {
344  p2 = path.pointAtPercent(forward ? percent : 1 - percent);
345  float angle = path.angleAtPercent(forward ? percent : 1 - percent) / 180 * M_PI;
346  // float angle = getAngle(p,p2);
347 
348  float x = width;
349  float y = 0;
350  float newAngle = angle + offsetAngle;
351  newAngle *= -1;
352  float x2 = cos(newAngle) * x - sin(newAngle) * y;
353  float y2 = sin(newAngle) * x + cos(newAngle) * y;
354  hull.append(QPointF(x2, y2) + p2);
355 
356  if (painter)
357  {
358  painter->drawEllipse(hull.last(), 2, 2);
359  }
360  }
361  };
362 
363  if (painter)
364  {
365  painter->setPen(QPen(Qt::red, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
366  painter->setBrush(QBrush(Qt::red, Qt::NoBrush));
367  }
368 
369  addHull(true, 5);
370 
371  if (painter)
372  {
373  painter->setPen(QPen(Qt::green, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
374  painter->setBrush(QBrush(Qt::red, Qt::NoBrush));
375  }
376 
377  addHull(false, 5);
378 
379 
380  return hull;
381  }
382 
383  QColor
385  {
386  return this->color;
387  }
388 
389  void
390  TransitionItem::setColor(const QColor& color)
391  {
392  this->color = color;
393  update();
394  }
395 
396  QColor
398  {
399  return highlightColor;
400  }
401 
402  void
404  {
405  this->highlightColor = color;
406  }
407 
408  QPointF
409  TransitionItem::calcIntersection(statechartmodel::StateInstancePtr state,
410  const QPointF& supportPoint) const
411  {
412  QLineF centerLine(state->getBounds().center(), supportPoint);
413  return calcIntersection(state, centerLine, supportPoint);
414  }
415 
416  QPointF
417  TransitionItem::calcIntersection(statechartmodel::StateInstancePtr state,
418  QLineF centerLine,
419  const QPointF& supportPoint) const
420  {
421 
422  QPolygonF statePolygon(state->getBounds());
423  QPointF p1 = statePolygon.first();
424  QPointF p2;
425  QPointF intersectPoint;
426  QLineF polyLine;
427  bool found = false;
428 
429  for (int i = 1; i < statePolygon.count(); ++i)
430  {
431  p2 = statePolygon.at(i);
432  polyLine = QLineF(p1, p2);
433  QLineF::IntersectType intersectType = polyLine.intersect(centerLine, &intersectPoint);
434 
435  if (intersectType == QLineF::BoundedIntersection)
436  {
437  found = true;
438  break;
439  }
440 
441  p1 = p2;
442  }
443 
444 
445  if (!found)
446  {
447  // support point is IN the state
448  float minLength = std::numeric_limits<float>::max();
449 
450  for (int i = 1; i < statePolygon.count(); ++i)
451  {
452  QPointF curIntersectPoint;
453  p2 = statePolygon.at(i);
454  polyLine = QLineF(p1, p2);
455  QLineF::IntersectType intersectType =
456  polyLine.intersect(centerLine, &curIntersectPoint);
457 
458  if (intersectType == QLineF::UnboundedIntersection)
459  {
460  float length = QLineF(supportPoint, curIntersectPoint).length();
461 
462  if (length < minLength)
463  {
464  intersectPoint = curIntersectPoint;
465  minLength = length;
466  }
467  }
468 
469  p1 = p2;
470  }
471  }
472 
473  return intersectPoint;
474  }
475 
476  QPolygonF
477  TransitionItem::calcArrowHead(const QLineF& line)
478  {
479  qreal arrowSize = 15;
480 
481  double angle = ::acos(line.dx() / line.length());
482 
483  if (line.dy() >= 0)
484  {
485  angle = (M_PI * 2) - angle;
486  }
487 
488  QPointF arrowP1 = line.p1() + QPointF(sin(angle + M_PI / 3) * arrowSize,
489  cos(angle + M_PI / 3) * arrowSize);
490  QPointF arrowP2 = line.p1() + QPointF(sin(angle + M_PI - M_PI / 3) * arrowSize,
491  cos(angle + M_PI - M_PI / 3) * arrowSize);
492 
493  QPolygonF arrowHead;
494  arrowHead << line.p1() << arrowP1 << arrowP2;
495 
496  return arrowHead;
497  }
498 
499  void
500  TransitionItem::recalcLabelPose()
501  {
502  if (!transitionLabel)
503  {
504  return;
505  }
506 
507  QPainterPath curPath = path();
508 
509  if (curPath.elementCount() < 2)
510  {
511  return;
512  }
513 
514  QPointF startPoint = curPath.elementAt(0);
515  QPointF endPoint = curPath.elementAt(curPath.elementCount() - 1);
516  QRectF transitionLabelRect = transitionLabel->boundingRect();
517 
518  float transitionLength = calcLengthOfLine(startPoint, endPoint);
519  ARMARX_CHECK_EXPRESSION(transitionLength == transitionLength);
520 
521  if (transitionLength == 0)
522  {
523  transitionLength = 1;
524  }
525  float labelAngle = 0;
526  //set position and angle of the transition label
527  QPointF newPos;
528  if (transition->labelCenterPosition)
529  {
530  // ARMARX_INFO_S << "Using precalculated label position";
531  if (transition->labelFontPointSize)
532  {
533  // ARMARX_INFO_S << "Using precalculated label font size";
534  transitionLabel->setBaseFontPointSize(*transition->labelFontPointSize);
535  transitionLabel->setFontPointSize(*transition->labelFontPointSize);
536  }
537  if (transitionLabel->rotation() != 0)
538  {
539  transitionLabel->setRotation(0);
540  }
541  newPos = *transition->labelCenterPosition -
542  QPointF(transitionLabel->boundingRect().width() * 0.5,
543  transitionLabel->boundingRect().height() * 0.5);
544  }
545  else
546  {
547  //angle between x direction and edge
548  float diff = (endPoint.x() - startPoint.x()) / transitionLength;
549  diff = std::max(-1.0f, diff);
550  diff = std::min(1.0f, diff);
551  labelAngle = acos(diff);
552 
553  if (labelAngle != labelAngle)
554  {
555  ARMARX_WARNING << VAROUT(diff) << "; " << VAROUT(acos(diff));
556  }
557 
558  int arg = 1;
559 
560  if (endPoint.y() - startPoint.y() < 0)
561  {
562  labelAngle = -labelAngle; //angle is negative if end is lower than start
563  }
564 
565  //adjust angle if end is to the left of start
566  if (endPoint.x() - startPoint.x() < 0)
567  {
568  labelAngle = M_PI + labelAngle;
569  arg = -1;
570  }
571  newPos.setX(path().pointAtPercent(0.5).x() - arg * transitionLabelRect.width() * 0.5 *
572  (endPoint.x() - startPoint.x()) /
573  transitionLength);
574  newPos.setY(path().pointAtPercent(0.5).y() - arg * transitionLabelRect.width() * 0.5 *
575  (endPoint.y() - startPoint.y()) /
576  transitionLength);
577  double newAngle = labelAngle * 180.0 / M_PI;
578  if (newAngle == newAngle)
579  {
580  if (transitionLabel->rotation() != newAngle)
581  {
582  transitionLabel->setRotation(newAngle);
583  }
584  }
585  else
586  {
587  ARMARX_WARNING << "Angle is NaN";
588  }
589  }
590 
591  transitionLabel->setPos(newPos);
592  }
593 
594  float
595  TransitionItem::calcLengthOfLine(QPointF start, QPointF end)
596  {
597  float xDiff = end.x() - start.x();
598  float yDiff = end.y() - start.y();
599  return sqrt(pow(xDiff, 2) + pow(yDiff, 2));
600  }
601 
604  {
605  return transition;
606  }
607 
608  void
609  TransitionItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
610  {
611  // ARMARX_INFO << "hoverEnterEvent " << transition->eventName;
612  // QFont font = transitionLabel->font();
613  // font.setPointSizeF(font.pointSizeF() * 2);
614  // transitionLabel->setFont(font);
615  QGraphicsView* view = getView(event);
616  if (view)
617  {
618  QRectF sceneScale = mapToScene(0.0f, 0.0f, 100.0f, 100.0f).boundingRect();
619  QRectF globalScale = view->mapFromScene(sceneScale).boundingRect();
620  float scale = globalScale.width();
621  float newFontSize = transitionLabel->baseFontPointSize() / (scale / 100);
622  transitionLabel->setEnlargedFontPointSize(newFontSize);
623  }
624  setColor(Qt::gray);
625  update();
626  transitionLabel->setHovering(true);
627  transitionLabel->update();
628  if (view && arrowHead.containsPoint(event->pos(), Qt::OddEvenFill))
629  {
630  view->viewport()->setCursor(Qt::OpenHandCursor);
631  }
632  }
633 
634  void
635  TransitionItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
636  {
637  QGraphicsView* view = getView(event);
638  if (view)
639  {
640  if (arrowHead.containsPoint(event->pos(), Qt::OddEvenFill))
641  {
642  view->viewport()->setCursor(Qt::OpenHandCursor);
643  }
644  else
645  {
646  view->viewport()->setCursor(Qt::ArrowCursor);
647  }
648  }
649  }
650 
651  void
652  TransitionItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
653  {
654  // ARMARX_INFO << "hoverLeaveEvent " << transition->eventName;
655  // QFont font = transitionLabel->font();
656  // font.setPointSizeF(font.pointSizeF() / 2);
657  // transitionLabel->setFont(font);
658  setColor(normalColor);
659  update();
660  transitionLabel->setHovering(false);
661 
662  transitionLabel->update();
663  QGraphicsView* view = getView(event);
664  if (view)
665  {
666  view->viewport()->setCursor(Qt::ArrowCursor);
667  }
668  }
669 
670  void
671  TransitionItem::paint(QPainter* painter,
672  const QStyleOptionGraphicsItem* option,
673  QWidget* widget)
674  {
675  // ARMARX_INFO << "painting transition";
676  if (!transition || (!transition->sourceState && !transition->destinationState))
677  {
678  return;
679  }
680 
681  StateItem* parentState = qgraphicsitem_cast<StateItem*>(parentItem());
682  LevelOfDetail detail = getLevelOfDetailByParent(painter, parentState);
683 
684  if (detail == eHidden)
685  // only use scale of parent so that all sub elements of parent (states, transitions) are hidden at once and not one after the other
686  {
687  return;
688  }
689 
690  painter->setBrush(QBrush(Qt::black, Qt::NoBrush));
691  painter->setPen(QPen(Qt::black, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
692  recalcLabelPose();
693  QColor tempColor = color;
694 
695  if (isSelected())
696  {
697  tempColor = Qt::darkGray;
698  // tempColor = tempColor.darker();
699  // QPainterPath curPath = path();
700  // for(int i = 1; i < curPath.elementCount()-1; i++)
701  // {
702  // painter->drawEllipse(curPath.elementAt(i), 1,1);
703  // }
704  }
705  // else if (option->state & QStyle::State_MouseOver)
706  // {
707  // ARMARX_INFO << "Mouse over transition";
708  // }
709  else if (transition && !transition->destinationState)
710  {
711  tempColor = Qt::darkRed;
712  }
713 
714 
715  QPen myPen = pen();
716  myPen.setColor(tempColor);
717 
718  painter->setPen(myPen);
719  painter->setBrush(QBrush(tempColor, Qt::NoBrush));
720  setBrush(QBrush(tempColor, Qt::NoBrush));
721  setPen(QPen(tempColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
722  painter->drawPath(path());
723  // QGraphicsPathItem::paint(painter, option, widget);
724  // QPen myPen = pen();
725 
726  myPen.setColor(tempColor);
727 
728  painter->setPen(myPen);
729  painter->setBrush(tempColor);
730  QPainterPath p = path();
731 
732  if (p.elementCount() < 2)
733  {
734  return;
735  }
736 
737  QPointF p1 = p.elementAt(p.elementCount() - 1);
738  QPointF p2 = p.elementAt(p.elementCount() - 2);
739  QLineF line(p1, p2);
740 
741  arrowHead = calcArrowHead(line);
742  painter->drawPolygon(arrowHead);
743 
744 
745  if (!transition->sourceState) // circle for start state transition
746  {
747  painter->drawEllipse(initialStateCircle);
748  }
749 
750  // auto hull = calcHull(0);
751  if (isSelected())
752  {
753  painter->setPen(QPen(Qt::gray, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
754  painter->setBrush(QBrush(Qt::red, Qt::NoBrush));
755  painter->drawPolygon(shapePolygon);
756  }
757  }
758 
759  void
760  TransitionItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
761  {
762  // ARMARX_INFO_S << "mouse pos: " << event->pos();
763  if (event->button() == Qt::LeftButton)
764  {
765  if (arrowHead.containsPoint(event->pos(), Qt::OddEvenFill))
766  {
767  pointAttachedToMouse = path().elementCount() - 1;
768  }
769  else
770  {
771  QPainterPath curPath = path();
772 
773  for (int i = 1; i < curPath.elementCount() - 1; i++)
774  {
775  QPointF point = curPath.elementAt(i);
776  QRectF rect(point.x() - 5, point.y() - 5, 10, 10);
777 
778  if (rect.contains(event->pos()))
779  {
780  pointAttachedToMouse = i;
781  ARMARX_INFO_S << VAROUT(rect) << " attached to point "
782  << pointAttachedToMouse << "/" << curPath.elementCount();
783  break;
784  }
785  }
786  }
787  }
788  else if (event->button() == Qt::RightButton)
789  {
790  event->accept();
791  scene()->clearSelection();
792  QMetaObject::invokeMethod(this, "setSelected", Qt::QueuedConnection, Q_ARG(bool, true));
793  }
794  else
795  {
796  QGraphicsPathItem::mousePressEvent(event);
797  }
798 
799  // ARMARX_INFO_S << VAROUT(pointAttachedToMouse);
800  }
801 
802  void
803  TransitionItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
804  {
805  // ARMARX_INFO_S << "buttonDownPos dist: " << (event->buttonDownPos(Qt::LeftButton)-event->pos()).manhattanLength() ;
806  if ((event->buttonDownPos(Qt::LeftButton) - event->pos()).manhattanLength() > 10)
807  {
808 
809  // ARMARX_INFO_S << VAROUT(event->pos()) << ": " << VAROUT(pointAttachedToMouse);
810  if (pointAttachedToMouse >= 0 && pointAttachedToMouse < path().elementCount())
811  {
812  // ARMARX_INFO_S << VAROUT(path().elementCount()) << ": " << VAROUT(pointAttachedToMouse);
813  QPainterPath p = path();
814  p.setElementPositionAt(pointAttachedToMouse, event->pos().x(), event->pos().y());
815  setPath(p);
816  recalcLabelPose();
817  recalcShape();
818  }
819  }
820 
821  QGraphicsPathItem::mouseMoveEvent(event);
822  }
823 
824  void
825  TransitionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
826  {
827 
828  if ((event->buttonDownPos(Qt::LeftButton) - event->pos()).manhattanLength() > 10 &&
829  pointAttachedToMouse == path().elementCount() - 1)
830  {
831  emit transitionEndPlaced(transition, event->pos());
832  recalcLabelPose();
833  }
834 
835  pointAttachedToMouse = -1;
836  QGraphicsPathItem::mouseReleaseEvent(event);
837  }
838 
839  void
840  TransitionItem::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
841  {
842  emit transitionContextMenuRequested(transition, event->screenPos(), event->pos());
843  }
844 
845  TransitionLabel::TransitionLabel(QString labelText, QGraphicsItem* parent) :
846  QGraphicsSimpleTextItem(labelText, parent),
847  MorphingItem(this),
848  animation(this, "fontPointSize")
849  {
851  // QFont currentFont = font();
852  // currentFont.setPointSize(fontBasePointSize);
854  hovering = false;
855  }
856 
857  void
858  TransitionLabel::paint(QPainter* painter,
859  const QStyleOptionGraphicsItem* option,
860  QWidget* widget)
861  {
862  if (parentItem())
863  {
864  StateItem* parentState = qgraphicsitem_cast<StateItem*>(parentItem()->parentItem());
865  LevelOfDetail detail = getLevelOfDetailByParent(painter, parentState);
866 
867  // only use scale of parent so that all sub elements of parent (states, transitions) are hidden at once and not one after the other
868  if (detail == eHidden)
869  {
870  return;
871  }
872  }
873  // float lod = QStyleOptionGraphicsItem::levelOfDetailFromTransform(painter->worldTransform());
874  // ARMARX_INFO_S << text().toStdString() << " LOD: " << lod << VAROUT(hovering);
875  // QFont currentFont = font();
876  // if (hovering)
877  // {
878  // float fontSize = currentFont.pointSizeF() * 2;
879  // if (fontSize * lod > fontMaxSize)
880  // {
881  // fontSize = fontMaxSize;
882  // }
883  // currentFont.setPointSizeF(fontSize);
884  // }
885  // else
886  // {
887  // currentFont.setPointSizeF(fontBasePointSize);
888  // }
889  // setFont(currentFont);
890  QGraphicsSimpleTextItem::paint(painter, option, widget);
891  }
892 
893  qreal
895  {
896  return font().pointSizeF();
897  }
898 
899  qreal
901  {
902  return fontBasePointSize;
903  }
904 
905  void
907  {
908  fontBasePointSize = newFontSize;
910  }
911 
912  void
914  {
915  QFont currentFont = font();
916  currentFont.setPointSizeF(newFontSize);
917  setFont(currentFont);
918  }
919 
920  void
922  {
924  }
925 
926  void
928  {
929  animation.stop();
930  animation.setDuration(200);
931  if (hovering)
932  {
933  animation.setKeyValueAt(0, fontPointSize());
934  animation.setKeyValueAt(1, fontEnlargedPointSize);
935  }
936  else
937  {
938  animation.setKeyValueAt(0, fontPointSize());
939  animation.setKeyValueAt(1, fontBasePointSize);
940  }
941 
942  animation.setEasingCurve(QEasingCurve::InOutQuad);
943  animation.start();
944  this->hovering = hovering;
945  }
946 
947  bool
949  {
950  return hovering;
951  }
952 
953 } // namespace armarx
armarx::TransitionItem::shapePolygon
QPolygonF shapePolygon
Definition: TransitionItem.h:97
armarx::TransitionLabel::getHovering
bool getHovering() const
Definition: TransitionItem.cpp:948
armarx::TransitionItem::getHighlightColor
QColor getHighlightColor() const
Definition: TransitionItem.cpp:397
armarx::TransitionLabel::setEnlargedFontPointSize
void setEnlargedFontPointSize(qreal newFontSize)
Definition: TransitionItem.cpp:921
armarx::TransitionItem::updateLabel
void updateLabel()
Definition: TransitionItem.cpp:299
armarx::TransitionItem::contextMenuEvent
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override
Definition: TransitionItem.cpp:840
armarx::MorphingItem::getView
static QGraphicsView * getView(QGraphicsSceneEvent *event)
Definition: MorphingItem.cpp:40
armarx::TransitionLabel::setBaseFontPointSize
void setBaseFontPointSize(qreal newFontSize)
Definition: TransitionItem.cpp:906
armarx::TransitionLabel::hovering
bool hovering
Definition: TransitionItem.h:145
armarx::TransitionItem::transitionContextMenuRequested
void transitionContextMenuRequested(statechartmodel::TransitionCPtr transition, QPoint mouseScreenPos, QPointF mouseItemPos)
armarx::TransitionLabel::fontPointSize
qreal fontPointSize
Definition: TransitionItem.h:129
armarx::TransitionItem::attachToMouse
void attachToMouse(int supportPointIndex)
Definition: TransitionItem.cpp:278
armarx::TransitionItem::paint
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
Definition: TransitionItem.cpp:671
StateItem.h
INITIAL_CIRCLE_RADIUS
#define INITIAL_CIRCLE_RADIUS
Definition: TransitionItem.cpp:48
armarx::TransitionLabel::animation
QPropertyAnimation animation
Definition: TransitionItem.h:144
detail
Definition: OpenCVUtil.cpp:128
armarx::TransitionLabel::TransitionLabel
TransitionLabel(QString labelText, QGraphicsItem *parent=0)
Definition: TransitionItem.cpp:845
armarx::TransitionItem::getColor
QColor getColor() const
Definition: TransitionItem.cpp:384
armarx::TransitionLabel::paint
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
Definition: TransitionItem.cpp:858
armarx::MorphingItem
Definition: MorphingItem.h:39
armarx::statechartmodel::StateInstancePtr
std::shared_ptr< StateInstance > StateInstancePtr
Definition: StateInstance.h:146
armarx::TransitionItem::recalcPath
void recalcPath()
Definition: TransitionItem.cpp:138
armarx::eHidden
@ eHidden
Definition: MorphingItem.h:37
armarx::SplinePath::simplePath
static QPainterPath simplePath(QPointList simpleControlPoints)
simplePath Constructs a cubic Beziercurve with an arbitrary number of control points.
Definition: SplinePath.cpp:36
armarx::TransitionItem::boundingRect
QRectF boundingRect() const override
Definition: TransitionItem.cpp:103
armarx::TransitionItem::mousePressEvent
void mousePressEvent(QGraphicsSceneMouseEvent *event) override
Definition: TransitionItem.cpp:760
armarx::SupportPoints::startPoint
QPointPtr startPoint
Definition: Transition.h:52
armarx::TransitionItem::highlightAnimation
void highlightAnimation(int duration=5000)
Definition: TransitionItem.cpp:284
armarx::TransitionItem::setEditable
void setEditable(bool editable)
Definition: TransitionItem.cpp:132
M_PI
#define M_PI
Definition: MathTools.h:17
armarx::TransitionItem::recalcShape
void recalcShape()
Definition: TransitionItem.cpp:266
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
armarx::TransitionItem::setColor
void setColor(const QColor &color)
Definition: TransitionItem.cpp:390
armarx::TransitionItem::mouseReleaseEvent
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override
Definition: TransitionItem.cpp:825
armarx::TransitionItem::hoverEnterEvent
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override
Definition: TransitionItem.cpp:609
armarx::TransitionItem::mouseMoveEvent
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override
Definition: TransitionItem.cpp:803
max
T max(T t1, T t2)
Definition: gdiam.h:51
armarx::SupportPoints::endPoint
QPointPtr endPoint
Definition: Transition.h:53
armarx::TransitionLabel::fontEnlargedPointSize
qreal fontEnlargedPointSize
Definition: TransitionItem.h:147
armarx::TransitionLabel
Definition: TransitionItem.h:126
armarx::TransitionItem::getTransition
statechartmodel::TransitionCPtr getTransition() const
Definition: TransitionItem.cpp:603
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::MorphingItem::getLevelOfDetailByParent
virtual LevelOfDetail getLevelOfDetailByParent(QPainter *painter, MorphingItem *parent) const
Definition: MorphingItem.cpp:79
armarx::armem::server::ltm::util::mongodb::detail::update
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
Definition: mongodb.cpp:68
armarx::red
QColor red()
Definition: StyleSheets.h:78
TransitionItem.h
armarx::TransitionItem::isInitialTransition
bool isInitialTransition() const
Definition: TransitionItem.cpp:121
ExpressionException.h
GfxTL::sqrt
VectorXD< D, T > sqrt(const VectorXD< D, T > &a)
Definition: VectorXD.h:704
armarx::TransitionItem::color
QColor color
Definition: TransitionItem.h:53
option
#define option(type, fn)
ARMARX_CHECK_EXPRESSION
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
Definition: ExpressionException.h:73
ArmarXWidgetController.h
SplinePath.h
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:198
armarx::TransitionLabel::fontBasePointSize
qreal fontBasePointSize
Definition: TransitionItem.h:146
armarx::SupportPoints::controlPoints
QPointList controlPoints
Definition: Transition.h:54
armarx::statechartmodel::TransitionCPtr
std::shared_ptr< const Transition > TransitionCPtr
Definition: Transition.h:91
armarx::TransitionItem::setSelected
void setSelected(bool selected)
Definition: TransitionItem.cpp:272
angle
double angle(const Point &a, const Point &b, const Point &c)
Definition: point.hpp:109
armarx::TransitionItem::getLastHighlightTimestamp
IceUtil::Time getLastHighlightTimestamp() const
Definition: TransitionItem.cpp:81
armarx::StateItem
Definition: StateItem.h:58
armarx::TransitionItem::hoverMoveEvent
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override
Definition: TransitionItem.cpp:635
armarx::TransitionItem::hoverLeaveEvent
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override
Definition: TransitionItem.cpp:652
ARMARX_INFO_S
#define ARMARX_INFO_S
Definition: Logging.h:202
armarx::LevelOfDetail
LevelOfDetail
Definition: MorphingItem.h:33
armarx::SupportPoints
Definition: Transition.h:42
armarx::TransitionLabel::setHovering
void setHovering(bool hovering)
Definition: TransitionItem.cpp:927
armarx::TransitionItem::transitionEndPlaced
void transitionEndPlaced(statechartmodel::TransitionCPtr transition, QPointF dropPosition)
min
T min(T t1, T t2)
Definition: gdiam.h:44
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::TransitionLabel::setFontPointSize
void setFontPointSize(qreal newFontSize)
Definition: TransitionItem.cpp:913
armarx::TransitionItem::setHighlightColor
void setHighlightColor(const QColor &color)
Definition: TransitionItem.cpp:403
armarx::TransitionItem::TransitionItem
TransitionItem(statechartmodel::TransitionCPtr transition, QGraphicsItem *parent=0)
Definition: TransitionItem.cpp:53
armarx::TransitionItem::shape
QPainterPath shape() const override
Definition: TransitionItem.cpp:87
armarx::TransitionItem::calcHull
QPolygonF calcHull(QPainter *painter=0) const
Definition: TransitionItem.cpp:318
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::TransitionLabel::baseFontPointSize
qreal baseFontPointSize() const
Definition: TransitionItem.cpp:900
armarx::green
QColor green()
Definition: StyleSheets.h:72
armarx::TransitionItem::highlightColor
QColor highlightColor
Definition: TransitionItem.h:54
armarx::SupportPoints::toPointList
QList< QPointF > toPointList() const
Definition: GraphvizConverter.cpp:360