27 #include "../StateScene.h"
28 #include "../model/State.h"
29 #include "../model/Transition.h"
30 #include "../model/stateinstance/StateInstance.h"
31 #include "../model/StateMimeData.h"
37 #include <QGraphicsProxyWidget>
41 #include <QStyleOptionGraphicsItem>
42 #include <QGraphicsSceneContextMenuEvent>
43 #include <QMessageBox>
46 #define MAXFONTSIZE 300.0f
53 RoundRectItem(QRectF(0, 0, state->getClassSize().width(), state->getClassSize().height()),
71 if (
state->getStateClass())
85 StateItem* parentState = qgraphicsitem_cast<StateItem*>(parentItem());
113 bool showSubstates =
detail !=
eNoSubstates && stateClass && !stateClass->getSubstates().empty();
115 bool showStateClassName = stateClass && (
instanceName != stateClass->getStateName() );
117 const int renderFlags = Qt::TextSingleLine | Qt::AlignTop | Qt::AlignHCenter;
121 float instanceNameWidthRelative = showSubstates ? 0.5f : 0.8f;
124 float instanceNameScaleFactor = textRect.width() * instanceNameWidthRelative / painter->fontMetrics().width(
instanceName);
128 if (showStateClassName)
130 textRect.adjust(0, 10, 0, 0);
134 textRect.adjust(0, 20, 0, 0);
139 textRect.adjust(0, (
bounds.height() - painter->fontMetrics().height() * instanceNameScaleFactor) / 2, 0, 0);
143 qreal lodT = QStyleOptionGraphicsItem::levelOfDetailFromTransform(painter->worldTransform());
144 QFont f = painter->font();
146 f.setPointSizeF(std::min<float>(f.pointSizeF() * instanceNameScaleFactor, (maxFsize).height() / lodT));
148 float textHeightScale = 0.8;
151 if (showSubstates &&
state->getStateClass() && painter->fontMetrics().height() > 0.5 *
state->getStateClass()->margin.top())
153 float margin =
state->getStateClass()->margin.top();
154 float height = painter->fontMetrics().height();
155 float size = f.pointSizeF();
156 textHeightScale = margin / height;
157 if (showStateClassName)
159 textHeightScale *= 0.45;
163 textHeightScale *= 0.7;
165 f.setPointSizeF(size * textHeightScale);
173 if (showStateClassName && !stateClass->getStateName().isEmpty())
175 QString classNameText =
"[state: " + stateClass->getStateName() +
"]";
176 float instanceNamePointSize = f.pointSizeF();
177 float classNameScaleFactor = textRect.width() * 0.8f / painter->fontMetrics().width(classNameText);
181 textRect.adjust(0, painter->fontMetrics().height() * 1.0, 0, 0);
183 lodT = QStyleOptionGraphicsItem::levelOfDetailFromTransform(painter->worldTransform());
185 float classNamePointSize = textHeightScale * std::min<float>(f.pointSizeF() * classNameScaleFactor, (maxFsize).height() / lodT);
186 classNamePointSize =
std::min(classNamePointSize, instanceNamePointSize);
187 f.setPointSizeF(classNamePointSize);
190 painter->drawText(textRect, renderFlags, classNameText);
219 StateInstanceItemMap::iterator it =
subStates.find(substate);
229 connect(stateItem, SIGNAL(
stateItemMoved(QPointF)), substate.get(), SLOT(setPosition(QPointF)));
232 stateItem->setScale(substate->getScale());
234 stateItem->setPos(substate->getTopLeft());
235 stateItem->
setSize(substate->getClassSize());
247 StateInstanceItemMap::iterator it =
subStates.find(substate);
255 substateItem->setPos(substate->getTopLeft());
256 substateItem->
setSize(substate->getClassSize());
257 substateItem->setScale(substate->getScale());
275 StateInstanceItemMap::iterator it =
subStates.find(substate);
283 QPointer<StateItem> substateItem = it.value();
287 substateItem->prepareGeometryChange();
288 QObject::disconnect(substateItem);
289 delete substateItem.data();
318 TransitionMap::iterator it =
transitions.find(transition);
332 TransitionMap::iterator it =
transitions.find(transition);
340 QObject::disconnect(t);
349 TransitionMap::iterator it =
transitions.find(transition);
355 int highlightDuration = 10000;
374 if (t->sourceState ==
state || t->destinationState ==
state)
388 TransitionMap::iterator it =
transitions.find(transition);
391 StateInstanceItemMap::iterator itState =
subStates.begin();
393 for (; itState !=
subStates.end(); itState++)
396 QPointF dropPointMapped = item->mapFromParent(dropPoint);
398 if (item->contains(dropPointMapped))
402 QList<QPointF> suppPoint;
403 suppPoint.push_back(dropPoint);
404 state->getStateClass()->updateTransitionDestination(transition, item->
getStateInstance(), suppPoint);
409 state->getStateClass()->detachTransitionDestination(transition, dropPoint);
445 if (
state->getStateClass())
468 if (!
state->getStateClass())
473 const auto& ts =
state->getStateClass()->getTransitions(
true);
475 for (
int i = 0; i < ts.size(); i++)
480 const auto& sl =
state->getStateClass()->getSubstates();
482 for (
auto i = sl.begin(); i != sl.end(); i++)
499 switch (
state->getType())
503 QColor color(52, 152, 219);
506 color = color.lighter(130);
510 color = color.lighter(110);
518 QColor color(26, 188, 156);
521 color = color.lighter(130);
525 color = color.lighter(110);
531 case eDynamicRemoteState:
537 QColor color(241, 196, 15);
538 color = color.lighter(120);
569 if (
state->getStateClass())
571 auto desc =
state->getStateClass()->getDescription();
583 auto curScene = scene();
589 curScene->removeItem(t);
594 s->prepareGeometryChange();
598 curScene->removeItem(
s);
606 const QGraphicsItem* parent =
this;
607 while (
dynamic_cast<StateItem*
>(parent->parentItem()))
609 parent = parent->parentItem();
619 return state->adjustPosition(newPos);
635 substate->setMaxShownSubstateLevel(
value);
637 for (
auto& item : childItems())
646 for (
auto substate : substates)
648 bool active = (substate->getInstanceName() == substateName);
649 substate->setActiveState(
active);
656 for (
auto substate : substates)
658 substate->setActiveState(
false);
665 StateItem* parent = qgraphicsitem_cast<StateItem*>(parentItem());
669 parent = qgraphicsitem_cast<StateItem*>(parent->parentItem());
676 StateItem* parent = qgraphicsitem_cast<StateItem*>(parentItem());
682 QVector<StateItem*> result;
683 for (QGraphicsItem* item : this->childItems())
688 result.push_back(
state);
696 QVector<TransitionItem*> result;
697 for (QGraphicsItem* item : this->childItems())
702 result.push_back(transition);
730 if (!
state->getStateClass())
742 if (oldSize != newSize)
751 if (oldPos != newPos)
780 scene()->clearSelection();
783 this->setSelected(
true);
791 if (change == ItemSelectedHasChanged &&
value.toBool() ==
true)
796 else if (change == ItemSelectedHasChanged &&
value.toBool() ==
false)
801 else if (change == ItemScaleHasChanged)
808 else if (change == ItemSceneChange)
843 event->setDropAction(Qt::LinkAction);
847 event->setDropAction(Qt::IgnoreAction);
863 if (event->proposedAction() == Qt::IgnoreAction)
871 && (
state->getType() == eNormalState ||
state->getType() == eRemoteState))
874 const QString newStateNameBase = data->
getState()->getStateName();
875 QString newStateName = newStateNameBase;
877 while (
state->getStateClass()->getSubstates().find(newStateName) !=
state->getStateClass()->getSubstates().end())
879 newStateName = newStateNameBase +
"_" + QString::number(i);
885 QMessageBox::warning(event->source(),
"State drag'n'drop error",
"State cycle detected - you must not insert a state which is also a parent state of the current state");
890 QMessageBox::warning(event->source(),
"State drag'n'drop error",
"Dynamic Remote States can only be added in the same group.");
895 if (data->
getState()->getType() == eDynamicRemoteState)
897 state->getStateClass()->addDynamicRemoteSubstate(data->
getState(), newStateName, event->pos());
901 state->getStateClass()->addSubstate(data->
getState(), newStateName, event->pos());
910 QMessageBox::warning(event->source(),
"State drag'n'drop error",
"Only public states can be added as a Remote State.");
924 event->setDropAction(Qt::LinkAction);
929 event->setDropAction(Qt::IgnoreAction);
946 if (!
state->getStateInstance() || !
state->getStateInstance()->getStateClass())
951 if (
state->getStateInstance()->getStateClass()->getUUID() == sC->getUUID())
956 return state->hasAncestor(sC);
961 if (!sC || !
state->getStateClass())
965 return state->getStateClass()->hasDescendant(sC);