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 =
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 / painter->fontMetrics().width(
instanceName);
130 if (showStateClassName)
132 textRect.adjust(0, 10, 0, 0);
136 textRect.adjust(0, 20, 0, 0);
141 textRect.adjust(0, (
bounds.height() - painter->fontMetrics().height() * instanceNameScaleFactor) / 2, 0, 0);
145 qreal lodT = QStyleOptionGraphicsItem::levelOfDetailFromTransform(painter->worldTransform());
146 QFont f = painter->font();
148 f.setPointSizeF(std::min<float>(f.pointSizeF() * instanceNameScaleFactor, (maxFsize).height() / lodT));
150 float textHeightScale = 0.8;
153 if (showSubstates &&
state->getStateClass() && painter->fontMetrics().height() > 0.5 *
state->getStateClass()->margin.top())
155 float margin =
state->getStateClass()->margin.top();
156 float height = painter->fontMetrics().height();
157 float size = f.pointSizeF();
158 textHeightScale = margin / height;
159 if (showStateClassName)
161 textHeightScale *= 0.45;
165 textHeightScale *= 0.7;
167 f.setPointSizeF(size * textHeightScale);
175 if (showStateClassName && !stateClass->getStateName().isEmpty())
177 QString classNameText =
"[state: " + stateClass->getStateName() +
"]";
178 float instanceNamePointSize = f.pointSizeF();
179 float classNameScaleFactor = textRect.width() * 0.8f / painter->fontMetrics().width(classNameText);
183 textRect.adjust(0, painter->fontMetrics().height() * 1.0, 0, 0);
185 lodT = QStyleOptionGraphicsItem::levelOfDetailFromTransform(painter->worldTransform());
187 float classNamePointSize = textHeightScale * std::min<float>(f.pointSizeF() * classNameScaleFactor, (maxFsize).height() / lodT);
188 classNamePointSize =
std::min(classNamePointSize, instanceNamePointSize);
189 f.setPointSizeF(classNamePointSize);
192 painter->drawText(textRect, renderFlags, classNameText);
221 StateInstanceItemMap::iterator it =
subStates.find(substate);
231 connect(stateItem, SIGNAL(
stateItemMoved(QPointF)), substate.get(), SLOT(setPosition(QPointF)));
234 stateItem->setScale(substate->getScale());
236 stateItem->setPos(substate->getTopLeft());
237 stateItem->
setSize(substate->getClassSize());
249 StateInstanceItemMap::iterator it =
subStates.find(substate);
257 substateItem->setPos(substate->getTopLeft());
258 substateItem->
setSize(substate->getClassSize());
259 substateItem->setScale(substate->getScale());
277 StateInstanceItemMap::iterator it =
subStates.find(substate);
285 QPointer<StateItem> substateItem = it.value();
289 substateItem->prepareGeometryChange();
290 QObject::disconnect(substateItem);
291 delete substateItem.data();
320 TransitionMap::iterator it =
transitions.find(transition);
334 TransitionMap::iterator it =
transitions.find(transition);
342 QObject::disconnect(t);
351 TransitionMap::iterator it =
transitions.find(transition);
357 int highlightDuration = 10000;
376 if (t->sourceState ==
state || t->destinationState ==
state)
390 TransitionMap::iterator it =
transitions.find(transition);
393 StateInstanceItemMap::iterator itState =
subStates.begin();
395 for (; itState !=
subStates.end(); itState++)
398 QPointF dropPointMapped = item->mapFromParent(dropPoint);
400 if (item->contains(dropPointMapped))
404 QList<QPointF> suppPoint;
405 suppPoint.push_back(dropPoint);
406 state->getStateClass()->updateTransitionDestination(transition, item->
getStateInstance(), suppPoint);
411 state->getStateClass()->detachTransitionDestination(transition, dropPoint);
447 if (
state->getStateClass())
470 if (!
state->getStateClass())
475 const auto& ts =
state->getStateClass()->getTransitions(
true);
477 for (
int i = 0; i < ts.size(); i++)
482 const auto& sl =
state->getStateClass()->getSubstates();
484 for (
auto i = sl.begin(); i != sl.end(); i++)
501 switch (
state->getType())
505 QColor color(52, 152, 219);
508 color = color.lighter(130);
512 color = color.lighter(110);
520 QColor color(26, 188, 156);
523 color = color.lighter(130);
527 color = color.lighter(110);
533 case eDynamicRemoteState:
539 QColor color(241, 196, 15);
540 color = color.lighter(120);
571 if (
state->getStateClass())
573 auto desc =
state->getStateClass()->getDescription();
585 auto curScene = scene();
591 curScene->removeItem(t);
596 s->prepareGeometryChange();
600 curScene->removeItem(
s);
608 const QGraphicsItem* parent =
this;
609 while (
dynamic_cast<StateItem*
>(parent->parentItem()))
611 parent = parent->parentItem();
621 return state->adjustPosition(newPos);
637 substate->setMaxShownSubstateLevel(
value);
639 for (
auto& item : childItems())
648 for (
auto substate : substates)
650 bool active = (substate->getInstanceName() == substateName);
651 substate->setActiveState(
active);
658 for (
auto substate : substates)
660 substate->setActiveState(
false);
667 StateItem* parent = qgraphicsitem_cast<StateItem*>(parentItem());
671 parent = qgraphicsitem_cast<StateItem*>(parent->parentItem());
678 StateItem* parent = qgraphicsitem_cast<StateItem*>(parentItem());
684 QVector<StateItem*> result;
685 for (QGraphicsItem* item : this->childItems())
690 result.push_back(
state);
698 QVector<TransitionItem*> result;
699 for (QGraphicsItem* item : this->childItems())
704 result.push_back(transition);
732 if (!
state->getStateClass())
744 if (oldSize != newSize)
753 if (oldPos != newPos)
782 scene()->clearSelection();
785 this->setSelected(
true);
793 if (change == ItemSelectedHasChanged &&
value.toBool() ==
true)
798 else if (change == ItemSelectedHasChanged &&
value.toBool() ==
false)
803 else if (change == ItemScaleHasChanged)
810 else if (change == ItemSceneChange)
845 event->setDropAction(Qt::LinkAction);
849 event->setDropAction(Qt::IgnoreAction);
865 if (event->proposedAction() == Qt::IgnoreAction)
873 && (
state->getType() == eNormalState ||
state->getType() == eRemoteState))
876 const QString newStateNameBase =
data->getState()->getStateName();
877 QString newStateName = newStateNameBase;
879 while (
state->getStateClass()->getSubstates().find(newStateName) !=
state->getStateClass()->getSubstates().end())
881 newStateName = newStateNameBase +
"_" + QString::number(i);
887 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 else if (
data->getState()->getType() == eDynamicRemoteState && !
data->isInSameGroup(
state->getStateClass()))
892 QMessageBox::warning(event->source(),
"State drag'n'drop error",
"Dynamic Remote States can only be added in the same group.");
895 else if (
data->isInSameGroup(
state->getStateClass()))
897 if (
data->getState()->getType() == eDynamicRemoteState)
899 state->getStateClass()->addDynamicRemoteSubstate(
data->getState(), newStateName, event->pos());
903 state->getStateClass()->addSubstate(
data->getState(), newStateName, event->pos());
906 else if (
data->isPublic())
908 state->getStateClass()->addRemoteSubstate(
data->getState(),
data->getProxyName(), newStateName, event->pos());
912 QMessageBox::warning(event->source(),
"State drag'n'drop error",
"Only public states can be added as a Remote State.");
926 event->setDropAction(Qt::LinkAction);
931 event->setDropAction(Qt::IgnoreAction);
948 if (!
state->getStateInstance() || !
state->getStateInstance()->getStateClass())
953 if (
state->getStateInstance()->getStateClass()->getUUID() == sC->getUUID())
958 return state->hasAncestor(sC);
963 if (!sC || !
state->getStateClass())
967 return state->getStateClass()->hasDescendant(sC);