26 #include <QGraphicsProxyWidget>
27 #include <QGraphicsSceneContextMenuEvent>
29 #include <QMessageBox>
31 #include <QStyleOptionGraphicsItem>
38 #include "../StateScene.h"
39 #include "../model/State.h"
40 #include "../model/StateMimeData.h"
41 #include "../model/Transition.h"
42 #include "../model/stateinstance/StateInstance.h"
46 #define MAXFONTSIZE 300.0f
51 RoundRectItem(QRectF(0, 0, state->getClassSize().width(), state->getClassSize().height()),
69 if (
state->getStateClass())
83 StateItem* parentState = qgraphicsitem_cast<StateItem*>(parentItem());
114 bool showStateClassName =
115 stateClass && (
instanceName != stateClass->getStateName() );
117 const int renderFlags =
static_cast<uint8_t
>(Qt::TextSingleLine) |
118 static_cast<uint8_t
>(Qt::AlignTop) |
119 static_cast<uint8_t
>(Qt::AlignHCenter);
123 float instanceNameWidthRelative = showSubstates ? 0.5f : 0.8f;
126 float instanceNameScaleFactor = textRect.width() * instanceNameWidthRelative /
131 if (showStateClassName)
133 textRect.adjust(0, 10, 0, 0);
137 textRect.adjust(0, 20, 0, 0);
144 (
bounds.height() - painter->fontMetrics().height() * instanceNameScaleFactor) / 2,
150 QStyleOptionGraphicsItem::levelOfDetailFromTransform(painter->worldTransform());
151 QFont f = painter->font();
154 std::min<float>(f.pointSizeF() * instanceNameScaleFactor, (maxFsize).height() / lodT));
156 float textHeightScale = 0.8;
159 if (showSubstates &&
state->getStateClass() &&
160 painter->fontMetrics().height() > 0.5 *
state->getStateClass()->margin.top())
162 float margin =
state->getStateClass()->margin.top();
163 float height = painter->fontMetrics().height();
164 float size = f.pointSizeF();
165 textHeightScale = margin / height;
166 if (showStateClassName)
168 textHeightScale *= 0.45;
172 textHeightScale *= 0.7;
174 f.setPointSizeF(size * textHeightScale);
182 if (showStateClassName && !stateClass->getStateName().isEmpty())
184 QString classNameText =
"[state: " + stateClass->getStateName() +
"]";
185 float instanceNamePointSize = f.pointSizeF();
186 float classNameScaleFactor =
187 textRect.width() * 0.8f / painter->fontMetrics().width(classNameText);
190 textRect.adjust(0, painter->fontMetrics().height() * 1.0, 0, 0);
192 lodT = QStyleOptionGraphicsItem::levelOfDetailFromTransform(painter->worldTransform());
194 float classNamePointSize =
196 std::min<float>(f.pointSizeF() * classNameScaleFactor, (maxFsize).height() / lodT);
197 classNamePointSize =
std::min(classNamePointSize,
198 instanceNamePointSize);
199 f.setPointSizeF(classNamePointSize);
202 painter->drawText(textRect, renderFlags, classNameText);
233 StateInstanceItemMap::iterator it =
subStates.find(substate);
246 SLOT(setPosition(QPointF)));
250 SLOT(setBoundingBox(
float)));
252 stateItem->setScale(substate->getScale());
254 stateItem->setPos(substate->getTopLeft());
255 stateItem->
setSize(substate->getClassSize());
267 StateInstanceItemMap::iterator it =
subStates.find(substate);
275 substateItem->setPos(substate->getTopLeft());
276 substateItem->
setSize(substate->getClassSize());
277 substateItem->setScale(substate->getScale());
293 StateInstanceItemMap::iterator it =
subStates.find(substate);
301 QPointer<StateItem> substateItem = it.value();
305 substateItem->prepareGeometryChange();
306 QObject::disconnect(substateItem);
307 delete substateItem.data();
345 TransitionMap::iterator it =
transitions.find(transition);
359 TransitionMap::iterator it =
transitions.find(transition);
367 QObject::disconnect(t);
375 TransitionMap::iterator it =
transitions.find(transition);
381 int highlightDuration = 10000;
402 if (t->sourceState ==
state || t->destinationState ==
state)
411 QPoint mouseScreenPos,
412 QPointF mouseItemPos)
415 transition,
state->getStateClass(), mouseScreenPos, mouseItemPos);
421 TransitionMap::iterator it =
transitions.find(transition);
424 StateInstanceItemMap::iterator itState =
subStates.begin();
426 for (; itState !=
subStates.end(); itState++)
429 QPointF dropPointMapped = item->mapFromParent(dropPoint);
431 if (item->contains(dropPointMapped))
435 QList<QPointF> suppPoint;
436 suppPoint.push_back(dropPoint);
437 state->getStateClass()->updateTransitionDestination(
443 state->getStateClass()->detachTransitionDestination(transition, dropPoint);
474 if (
state->getStateClass())
476 connect(
state->getStateClass().get(),
480 connect(
state->getStateClass().get(),
486 connect(
state->getStateClass().get(),
494 state->getStateClass().get(),
512 if (!
state->getStateClass())
517 const auto& ts =
state->getStateClass()->getTransitions(
true);
519 for (
int i = 0; i < ts.size(); i++)
524 const auto& sl =
state->getStateClass()->getSubstates();
526 for (
auto i = sl.begin(); i != sl.end(); i++)
540 switch (
state->getType())
544 QColor color(52, 152, 219);
547 color = color.lighter(130);
551 color = color.lighter(110);
559 QColor color(26, 188, 156);
562 color = color.lighter(130);
566 color = color.lighter(110);
572 case eDynamicRemoteState:
578 QColor color(241, 196, 15);
579 color = color.lighter(120);
610 if (
state->getStateClass())
612 auto desc =
state->getStateClass()->getDescription();
625 auto curScene = scene();
631 curScene->removeItem(t);
636 s->prepareGeometryChange();
640 curScene->removeItem(
s);
649 const QGraphicsItem* parent =
this;
650 while (
dynamic_cast<StateItem*
>(parent->parentItem()))
652 parent = parent->parentItem();
663 return state->adjustPosition(newPos);
681 substate->setMaxShownSubstateLevel(
value);
683 for (
auto& item : childItems())
693 for (
auto substate : substates)
695 bool active = (substate->getInstanceName() == substateName);
696 substate->setActiveState(
active);
704 for (
auto substate : substates)
706 substate->setActiveState(
false);
714 StateItem* parent = qgraphicsitem_cast<StateItem*>(parentItem());
718 parent = qgraphicsitem_cast<StateItem*>(parent->parentItem());
726 StateItem* parent = qgraphicsitem_cast<StateItem*>(parentItem());
733 QVector<StateItem*> result;
734 for (QGraphicsItem* item : this->childItems())
739 result.push_back(
state);
745 QVector<TransitionItem*>
748 QVector<TransitionItem*> result;
749 for (QGraphicsItem* item : this->childItems())
754 result.push_back(transition);
786 if (!
state->getStateClass())
797 if (oldSize != newSize)
807 if (oldPos != newPos)
836 scene()->clearSelection();
839 this->setSelected(
true);
847 if (change == ItemSelectedHasChanged &&
value.toBool() ==
true)
852 else if (change == ItemSelectedHasChanged &&
value.toBool() ==
false)
857 else if (change == ItemScaleHasChanged)
865 else if (change == ItemSceneChange)
924 qobject_cast<const AbstractStateMimeData*>(event->mimeData());
927 state->getType() == eNormalState)
929 event->setDropAction(Qt::LinkAction);
933 event->setDropAction(Qt::IgnoreAction);
949 if (event->proposedAction() == Qt::IgnoreAction)
955 qobject_cast<const AbstractStateMimeData*>(event->mimeData());
958 (
state->getType() == eNormalState ||
state->getType() == eRemoteState))
961 const QString newStateNameBase =
data->getState()->getStateName();
962 QString newStateName = newStateNameBase;
964 while (
state->getStateClass()->getSubstates().find(newStateName) !=
965 state->getStateClass()->getSubstates().end())
967 newStateName = newStateNameBase +
"_" + QString::number(i);
972 data->getState()->hasDescendant(
state->getStateClass()))
974 QMessageBox::warning(event->source(),
975 "State drag'n'drop error",
976 "State cycle detected - you must not insert a state which is "
977 "also a parent state of the current state");
980 else if (
data->getState()->getType() == eDynamicRemoteState &&
981 !
data->isInSameGroup(
state->getStateClass()))
983 QMessageBox::warning(event->source(),
984 "State drag'n'drop error",
985 "Dynamic Remote States can only be added in the same group.");
988 else if (
data->isInSameGroup(
state->getStateClass()))
990 if (
data->getState()->getType() == eDynamicRemoteState)
992 state->getStateClass()->addDynamicRemoteSubstate(
993 data->getState(), newStateName, event->pos());
997 state->getStateClass()->addSubstate(
998 data->getState(), newStateName, event->pos());
1001 else if (
data->isPublic())
1003 state->getStateClass()->addRemoteSubstate(
1004 data->getState(),
data->getProxyName(), newStateName, event->pos());
1008 QMessageBox::warning(event->source(),
1009 "State drag'n'drop error",
1010 "Only public states can be added as a Remote State.");
1022 event->setDropAction(Qt::LinkAction);
1027 event->setDropAction(Qt::IgnoreAction);
1045 if (!
state->getStateInstance() || !
state->getStateInstance()->getStateClass())
1050 if (
state->getStateInstance()->getStateClass()->getUUID() == sC->getUUID())
1055 return state->hasAncestor(sC);
1061 if (!sC || !
state->getStateClass())
1065 return state->getStateClass()->hasDescendant(sC);