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