File indexing completed on 2024-04-28 03:51:19

0001 /*.
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003     SPDX-FileCopyrightText: 2014 Inge Wallin <inge@lysator.liu.se>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "stepgraphicsitem.h"
0009 
0010 #include "settings.h"
0011 
0012 #include "worldmodel.h"
0013 #include <stepcore/object.h>
0014 #include <stepcore/world.h>
0015 #include <stepcore/particle.h>
0016 
0017 #include <QGraphicsScene>
0018 #include <QGraphicsSceneMouseEvent>
0019 #include <QItemSelectionModel>
0020 #include <QMenu>
0021 #include <QPainter>
0022 #include <QTimer>
0023 
0024 #include <KLocalizedString>
0025 
0026 #include <cmath>
0027 
0028 // XXX
0029 #include "worldscene.h"
0030 
0031 //XXX
0032 const QColor StepGraphicsItem::SELECTION_COLOR = QColor(0xff, 0x70, 0x70);
0033 
0034 
0035 /////////////////////////////////////////////////////////////////////////////////////////
0036 
0037 
0038 StepGraphicsItem::StepGraphicsItem(StepCore::Item* item, WorldModel* worldModel,
0039                    QGraphicsItem* parent)
0040     : QGraphicsItem(parent)
0041     , _item(item)
0042     , _worldModel(worldModel)
0043     , _exclusiveMoving(false)
0044     , _onHoverHandlerEnabled(false)
0045     , _isHighlighted(false)
0046     , _isMouseOverItem(false)
0047     , _isSelected(false)
0048     , _isMoving(false)
0049     , _onHoverHandler(nullptr)
0050     , _onHoverHandlerTimer(false)
0051 {
0052     // XXX: use persistent indexes here and in propertiesbrowser
0053     setZValue(BODY_ZVALUE);
0054 }
0055 
0056 double StepGraphicsItem::currentViewScale() const
0057 {
0058     if(!scene()) return 1;
0059     return static_cast<WorldScene*>(scene())->currentViewScale();
0060 }
0061 
0062 QColor StepGraphicsItem::highlightColor(const QColor& color)
0063 {
0064 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0065     float h, s, v, a;
0066 #else
0067     qreal h, s, v, a;
0068 #endif
0069     QColor hsv = color.toHsv();
0070     hsv.getHsvF(&h, &s, &v, &a);
0071 
0072     v += float(COLOR_HIGHLIGHT_AMOUNT)/100;
0073     if (v > 1.0) {
0074         // overflow... adjust saturation
0075         s -= v - 1.0;
0076         if (s < 0) s = 0.0;
0077         v = 1.0;
0078     }
0079 
0080     hsv.setHsvF(h, s, v, a);
0081 
0082     // convert back to same color spec as original color
0083     return hsv.convertTo(color.spec());
0084 }
0085 
0086 void StepGraphicsItem::drawArrow(QPainter* painter, const StepCore::Vector2d& r,
0087                                                      const StepCore::Vector2d& v)
0088 {
0089     double s = currentViewScale();
0090     if(v.squaredNorm()*s*s > ARROW_STROKE*ARROW_STROKE) { // do not draw too small vectors
0091         StepCore::Vector2d vv = r+v;
0092         painter->drawLine(QLineF(r[0], r[1], vv[0], vv[1]));
0093 
0094         const StepCore::Vector2d vn = v * (ARROW_STROKE / s / v.norm());
0095         painter->drawLine(QLineF(vv[0], vv[1], vv[0] - 0.866*vn[0] - 0.5  *vn[1],
0096                                                vv[1] + 0.5  *vn[0] - 0.866*vn[1]));
0097         painter->drawLine(QLineF(vv[0], vv[1], vv[0] - 0.866*vn[0] + 0.5  *vn[1],
0098                                                vv[1] - 0.5  *vn[0] - 0.866*vn[1]));
0099     }
0100 }
0101 
0102 void StepGraphicsItem::drawCircularArrow(QPainter* painter, const StepCore::Vector2d& r,
0103                                                     double angle, double radius)
0104 {
0105     double s = currentViewScale();
0106     double rs = radius/s;
0107     double x0 = rs*cos(angle)+r[0]/s;
0108     double y0 = rs*sin(angle)+r[1]/s;
0109     double xAr1 = CIRCULAR_ARROW_STROKE*cos(2*M_PI/3 + angle)/s;
0110     double yAr1 = CIRCULAR_ARROW_STROKE*sin(2*M_PI/3 + angle)/s;
0111     double xAr2 = CIRCULAR_ARROW_STROKE*cos(M_PI/3 + angle)/s;
0112     double yAr2 = CIRCULAR_ARROW_STROKE*sin(M_PI/3 + angle)/s;
0113 
0114     QRectF rr(-rs, -rs, 2*rs, 2*rs);
0115 
0116     if(angle > 2*M_PI || angle < -2*M_PI) {
0117         painter->drawArc(rr, int(-angle*180*16/M_PI-150*16), 300*16);
0118         for(int i=1; i<5; ++i)
0119             painter->drawArc(rr, int(-angle*180*16/M_PI-150*16-i*12*16), 1*16);
0120     } else if(angle > 0) {
0121         painter->drawArc(rr, -int(angle*180*16/M_PI), int(angle*180*16/M_PI));
0122     } else {
0123         painter->drawArc(rr, 0, int(-angle*180*16/M_PI));
0124     }
0125 
0126     // do not draw too small vectors
0127     if(angle > 0 && angle*radius > CIRCULAR_ARROW_STROKE) {
0128         painter->drawLine(QLineF(x0, y0, x0-xAr1, y0-yAr1));
0129         painter->drawLine(QLineF(x0, y0, x0-xAr2, y0-yAr2));
0130     } if(angle < 0 && -angle*radius > CIRCULAR_ARROW_STROKE) {
0131         painter->drawLine(QLineF(x0, y0, x0+xAr1, y0+yAr1));
0132         painter->drawLine(QLineF(x0, y0, x0+xAr2, y0+yAr2));
0133     }
0134 }
0135 
0136 void StepGraphicsItem::drawArrow(QPainter* painter, const StepCore::Vector2d& v)
0137 {
0138     drawArrow(painter, StepCore::Vector2d::Zero(), v);
0139 }
0140 
0141 void StepGraphicsItem::drawCircularArrow(QPainter* painter, double angle, double radius)
0142 {
0143     drawCircularArrow(painter, StepCore::Vector2d::Zero(), angle, radius);
0144 }
0145 
0146 void StepGraphicsItem::mouseSetPos(const QPointF& pos, const QPointF&, MovingState)
0147 {
0148     const StepCore::MetaProperty* property = _item->metaObject()->property(QStringLiteral("position"));
0149     if(property != nullptr) {
0150         _worldModel->simulationPause();
0151         _worldModel->setProperty(_item, property,
0152                                 QVariant::fromValue( pointToVector(pos) ));
0153     } else {
0154         Q_ASSERT(false);
0155     }
0156 }
0157 
0158 void StepGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
0159 {
0160     // Workaround for bug in Qt
0161     if (scene()->itemAt(event->scenePos(), QTransform()) != this) {
0162         event->ignore();
0163         return;
0164     }
0165     
0166     if(event->button() == Qt::LeftButton && (flags() & ItemIsSelectable)) {
0167         bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
0168         if(!multiSelect && !isSelected()) {
0169             if(scene()) scene()->clearSelection();
0170             _worldModel->selectionModel()->clearSelection();
0171             setSelected(true);
0172         }
0173     } else if (!(flags() & ItemIsMovable)) {
0174         event->ignore();
0175     }
0176 }
0177 
0178 void StepGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
0179 {
0180     // Workaround for bug in Qt
0181     if (scene()->mouseGrabberItem() != this &&
0182         scene()->itemAt(event->scenePos(), QTransform()) != this) {
0183         event->ignore();
0184         return;
0185     }
0186     
0187     if((event->buttons() & Qt::LeftButton) && (flags() & ItemIsMovable)) {
0188         QPointF pdiff(mapToParent(event->pos()) - mapToParent(event->lastPos()));
0189         QPointF newPos(mapToParent(event->pos()) - transform().map(event->buttonDownPos(Qt::LeftButton)));
0190 
0191         QPointF diff = newPos - pos();
0192         if(diff == QPointF(0, 0)) return;
0193 
0194         MovingState movingState = Moving;
0195         if(!_isMoving) {
0196             if(_exclusiveMoving) {
0197                 if(!_exclusiveMovingMessage.isEmpty()) _worldModel->beginMacro(_exclusiveMovingMessage);
0198                 else _worldModel->beginMacro(i18n("Move %1", _item->name()));
0199 
0200             } else {
0201                 int count = 0;
0202                 foreach(QGraphicsItem *item, scene()->selectedItems())
0203                     if(item != this && (item->flags() & ItemIsMovable) &&
0204                                 (!item->parentItem() || !item->parentItem()->isSelected()) &&
0205                                 dynamic_cast<StepGraphicsItem*>(item)) {
0206                         ++count;
0207                     }
0208                 if(!this->parentItem() || !this->parentItem()->isSelected()) ++count;
0209 
0210                 _worldModel->beginMacro(i18n("Move %1", count == 1 ? _item->name() : i18n("several objects")));
0211             }
0212 
0213             movingState = Started;
0214             _isMoving = true;
0215         }
0216 
0217         if(_exclusiveMoving) {
0218             mouseSetPos(newPos, pdiff, movingState);
0219         } else {
0220             // Move all selected items
0221             foreach(QGraphicsItem *item, scene()->selectedItems()) {
0222                 if(item != this && (item->flags() & ItemIsMovable) &&
0223                             (!item->parentItem() || !item->parentItem()->isSelected())) {
0224                     StepGraphicsItem* worldItem = dynamic_cast<StepGraphicsItem*>(item);
0225                     if(worldItem) worldItem->mouseSetPos(item->pos() + diff, pdiff, movingState);
0226                 }
0227             }
0228             if(!this->parentItem() || !this->parentItem()->isSelected())
0229                 mouseSetPos(newPos, pdiff, movingState);
0230         }
0231     } else {
0232         event->ignore();
0233     }
0234 }
0235 
0236 void StepGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
0237 {
0238     // Workaround for bug in Qt
0239     if (scene()->itemAt(event->scenePos(), QTransform()) != this) {
0240         event->ignore();
0241         return;
0242     }
0243     
0244     if(_isMoving && event->button() == Qt::LeftButton) {
0245         QPointF pdiff(mapToParent(event->pos()) - mapToParent(event->lastPos()));
0246         QPointF newPos(mapToParent(event->pos()) - transform().map(event->buttonDownPos(Qt::LeftButton)));
0247         QPointF diff = newPos - pos();
0248 
0249         if(_exclusiveMoving) {
0250             mouseSetPos(newPos, pdiff, Finished);
0251         } else {
0252             foreach(QGraphicsItem *item, scene()->selectedItems()) {
0253                 if(item != this && (item->flags() & ItemIsMovable) &&
0254                             (!item->parentItem() || !item->parentItem()->isSelected())) {
0255                     StepGraphicsItem* worldItem = dynamic_cast<StepGraphicsItem*>(item);
0256                     if(worldItem) worldItem->mouseSetPos(item->pos() + diff, pdiff, Finished);
0257                 }
0258             }
0259             if(!this->parentItem() || !this->parentItem()->isSelected())
0260                 mouseSetPos(newPos, pdiff, Finished);
0261         }
0262 
0263         _worldModel->endMacro();
0264         _isMoving = false;
0265     }
0266     if(flags() & ItemIsSelectable) {
0267         bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
0268         if(event->scenePos() == event->buttonDownScenePos(Qt::LeftButton)) {
0269             // The item didn't move
0270             if (multiSelect) {
0271                 setSelected(!isSelected());
0272             } else {
0273                 if(scene()) scene()->clearSelection();
0274                 _worldModel->selectionModel()->clearSelection();
0275                 setSelected(true);
0276             }
0277         }
0278     }
0279 }
0280 
0281 void StepGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
0282 {
0283     if(_onHoverHandlerEnabled) {
0284         OnHoverHandlerGraphicsItem* newOnHoverHandler = createOnHoverHandler(event->scenePos());
0285         if(_onHoverHandler && !newOnHoverHandler) {
0286              if(!_onHoverHandlerTimer) {
0287                 _onHoverHandler->setDeleteTimerEnabled(true);
0288                 _onHoverHandlerTimer = true;
0289              }
0290         } else if(_onHoverHandler == newOnHoverHandler) {
0291             if(_onHoverHandler && _onHoverHandlerTimer) {
0292                 _onHoverHandler->setDeleteTimerEnabled(false);
0293                 _onHoverHandlerTimer = false;
0294             }
0295         } else {
0296             delete _onHoverHandler;
0297             _onHoverHandler = newOnHoverHandler;
0298             _onHoverHandlerTimer = false;
0299         }
0300     }
0301 }
0302 
0303 void StepGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
0304 {
0305     if(_onHoverHandlerEnabled && _onHoverHandler && !_onHoverHandlerTimer)
0306         _onHoverHandler->setDeleteTimerEnabled(false);
0307     _isMouseOverItem = true;
0308     stateChanged();
0309     //update(_boundingRect);
0310 }
0311 
0312 void StepGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
0313 {
0314     if(_onHoverHandlerEnabled && _onHoverHandler && !_onHoverHandlerTimer)
0315         _onHoverHandler->setDeleteTimerEnabled(true);
0316     _isMouseOverItem = false;
0317     stateChanged();
0318     //update(_boundingRect);
0319 }
0320 
0321 QVariant StepGraphicsItem::itemChange(GraphicsItemChange change, const QVariant& value)
0322 {
0323     if(change == ItemSelectedHasChanged && value.toBool() != _isSelected && scene()) {
0324         _isSelected = value.toBool();
0325         if(_isSelected) setZValue(zValue() + 1);
0326         else setZValue(zValue() - 1);
0327 
0328         QModelIndex index = _worldModel->objectIndex(_item);
0329         if(_isSelected && !_worldModel->selectionModel()->isSelected(index)) {
0330             _worldModel->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
0331         } else if(!_isSelected && _worldModel->selectionModel()->isSelected(index)) {
0332             _worldModel->selectionModel()->select(index, QItemSelectionModel::Deselect);
0333         }
0334 
0335         stateChanged();
0336     }
0337     return QGraphicsItem::itemChange(change, value);
0338 }
0339 
0340 void StepGraphicsItem::setOnHoverHandlerEnabled(bool enabled)
0341 {
0342     _onHoverHandlerEnabled = enabled;
0343     if(!_onHoverHandlerEnabled) {
0344         _onHoverHandlerTimer = false;
0345         delete _onHoverHandler;
0346     }
0347 }
0348 
0349 void StepGraphicsItem::viewScaleChanged()
0350 {
0351 }
0352 
0353 void StepGraphicsItem::worldDataChanged(bool)
0354 {
0355 }
0356 
0357 void StepGraphicsItem::stateChanged()
0358 {
0359 }
0360 
0361 void StepGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
0362 {
0363     painter->setPen(QPen(Qt::gray, 0));
0364     painter->drawRect(_boundingRect);
0365 }
0366 
0367 void StepGraphicsItem::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
0368 {
0369     event->accept();
0370 
0371     QModelIndex index = _worldModel->objectIndex(_item);
0372     if(flags() & QGraphicsItem::ItemIsSelectable)
0373         _worldModel->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
0374 
0375     QMenu* menu = _worldModel->createContextMenu(index);
0376     menu->exec(event->screenPos());
0377     delete menu;
0378 }
0379 
0380 /////////////////////////////////////////////////////////////////////////////////////////
0381 
0382 ArrowHandlerGraphicsItem::ArrowHandlerGraphicsItem(StepCore::Item* item, WorldModel* worldModel, 
0383                          QGraphicsItem* parent, const StepCore::MetaProperty* property,
0384                          const StepCore::MetaProperty* positionProperty)
0385     : StepGraphicsItem(item, worldModel, parent)
0386     , _property(property)
0387     , _positionProperty(positionProperty)
0388 {
0389     Q_ASSERT(!_property || _property->userTypeId() == qMetaTypeId<StepCore::Vector2d>());
0390     setFlag(QGraphicsItem::ItemIsMovable);
0391     setZValue(HANDLER_ZVALUE);
0392     _exclusiveMoving = true;
0393     if(_property) _exclusiveMovingMessage = i18n("Change %1.%2", _item->name(), _property->nameTr());
0394     else _exclusiveMovingMessage = i18n("Change %1", _item->name());
0395 }
0396 
0397 void ArrowHandlerGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/,
0398                      QWidget* /*widget*/)
0399 {
0400     painter->setPen(QPen(Qt::gray, 0));
0401     painter->drawRect(_boundingRect);
0402 }
0403 
0404 void ArrowHandlerGraphicsItem::viewScaleChanged()
0405 {
0406     if(isVisible()) {
0407         prepareGeometryChange();
0408         double w = HANDLER_SIZE/currentViewScale()/2;
0409         _boundingRect = QRectF(-w, -w, w*2, w*2);
0410     }
0411 }
0412 
0413 void ArrowHandlerGraphicsItem::worldDataChanged(bool)
0414 {
0415     if(isVisible()) {
0416         //qDebug() << "ArrowHandlerGraphicsItem::worldDataChanged()" << endl;
0417         setPos(vectorToPoint(value()));
0418     }
0419 }
0420 
0421 QVariant ArrowHandlerGraphicsItem::itemChange(GraphicsItemChange change, const QVariant& value)
0422 {
0423     if(change == QGraphicsItem::ItemVisibleHasChanged) {
0424         if(isVisible()) {
0425             viewScaleChanged();
0426             worldDataChanged(false);
0427         }
0428     }
0429     return StepGraphicsItem::itemChange(change, value);
0430 }
0431 
0432 void ArrowHandlerGraphicsItem::mouseSetPos(const QPointF& pos, const QPointF&, MovingState)
0433 {
0434     setValue(pointToVector(pos));
0435 }
0436 
0437 /*
0438 void ArrowHandlerGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
0439 {
0440     if ((event->buttons() & Qt::LeftButton) && (flags() & ItemIsMovable)) {
0441         if(!_isMoving) {
0442             if(_property)
0443                 _worldModel->beginMacro(i18n("Change %1.%2", _item->name(), _property->nameTr()));
0444             else
0445                 _worldModel->beginMacro(i18n("Change %1", _item->name()));
0446             _isMoving = true;
0447         }
0448         QPointF newPos(mapToParent(event->pos()) - matrix().map(event->buttonDownPos(Qt::LeftButton)));
0449         setValue(pointToVector(newPos));
0450         //_worldModel->simulationPause();
0451         //_worldModel->setProperty(_item, _property, QVariant::fromValue(pointToVector(newPos)));
0452         //Q_ASSERT(_property->writeVariant(_item, QVariant::fromValue(v)));
0453         //_worldModel->setData(_worldModel->objectIndex(_item), QVariant(), WorldModel::ObjectRole);
0454     } else  event->ignore();
0455 }*/
0456 
0457 StepCore::Vector2d ArrowHandlerGraphicsItem::value()
0458 {
0459     if(_property) {
0460         StepCore::Vector2d ret = _property->readVariant(_item).value<StepCore::Vector2d>();
0461         if(_positionProperty)
0462             ret += _positionProperty->readVariant(_item).value<StepCore::Vector2d>();
0463         return ret;
0464     } else {
0465         return StepCore::Vector2d::Zero();
0466     }
0467 }
0468 
0469 void ArrowHandlerGraphicsItem::setValue(const StepCore::Vector2d& value)
0470 {
0471     if(_property) {
0472         _worldModel->simulationPause();
0473         StepCore::Vector2d v = value;
0474         if(_positionProperty)
0475             v -= _positionProperty->readVariant(_item).value<StepCore::Vector2d>();
0476         _worldModel->setProperty(_item, _property, QVariant::fromValue(v));
0477     }
0478 }
0479 
0480 /////////////////////////////////////////////////////////////////////////////////////////
0481 
0482 CircularArrowHandlerGraphicsItem::CircularArrowHandlerGraphicsItem(StepCore::Item* item,
0483                                    WorldModel* worldModel, 
0484                          QGraphicsItem* parent, double radius,
0485                          const StepCore::MetaProperty* property,
0486                          const StepCore::MetaProperty* positionProperty)
0487     : StepGraphicsItem(item, worldModel, parent)
0488     , _property(property)
0489     , _positionProperty(positionProperty)
0490     , _radius(radius)
0491 {
0492     Q_ASSERT(!_property || _property->userTypeId() == qMetaTypeId<double>());
0493     setFlag(QGraphicsItem::ItemIsMovable);
0494     setZValue(HANDLER_ZVALUE);
0495 }
0496 
0497 void CircularArrowHandlerGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
0498 {
0499     painter->setPen(QPen(Qt::gray, 0));
0500     painter->drawRect(_boundingRect);
0501 }
0502 
0503 void CircularArrowHandlerGraphicsItem::viewScaleChanged()
0504 {
0505     if(isVisible()) {
0506         prepareGeometryChange();
0507         double w = HANDLER_SIZE/currentViewScale()/2;
0508         _boundingRect = QRectF(-w, -w, w*2, w*2);
0509         worldDataChanged(true);
0510     }
0511 }
0512 
0513 void CircularArrowHandlerGraphicsItem::worldDataChanged(bool)
0514 {
0515     if(isVisible()) {
0516         double s = currentViewScale();
0517         double angle = value();
0518         setPos(_radius*cos(angle)/s, _radius*sin(angle)/s);
0519     }
0520 }
0521 
0522 QVariant CircularArrowHandlerGraphicsItem::itemChange(GraphicsItemChange change, const QVariant& value)
0523 {
0524     if(change == QGraphicsItem::ItemVisibleHasChanged) {
0525         if(isVisible()) {
0526             viewScaleChanged();
0527             worldDataChanged(false);
0528         }
0529     }
0530     return StepGraphicsItem::itemChange(change, value);
0531 }
0532 
0533 void CircularArrowHandlerGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
0534 {
0535     if ((event->buttons() & Qt::LeftButton) && (flags() & ItemIsMovable)) {
0536         if(!_isMoving) {
0537             if(_property)
0538                 _worldModel->beginMacro(i18n("Change %1.%2", _item->name(), _property->nameTr()));
0539             else
0540                 _worldModel->beginMacro(i18n("Change %1", _item->name()));
0541             _isMoving = true;
0542         }
0543 
0544         QPointF newPos(mapToParent(event->pos()) - transform().map(event->buttonDownPos(Qt::LeftButton)));
0545         double newValue = atan2(newPos.y(),newPos.x());
0546         if(newValue < 0) newValue += 2*M_PI;
0547 
0548         double v = value();
0549         double b = 2*M_PI * int(v / (2*M_PI) - (v<0 ? 1 : 0));
0550         double f = v - b;
0551 
0552         if(f < M_PI_2 && newValue > 3*M_PI_2) newValue -= 2*M_PI;
0553         else if(f > 3*M_PI_2 && newValue < M_PI_2) newValue += 2*M_PI;
0554 
0555         setValue(b + newValue);
0556     } else event->ignore();
0557 }
0558 
0559 void CircularArrowHandlerGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
0560 {
0561     if(_isMoving && event->button() == Qt::LeftButton) {
0562         _worldModel->endMacro();
0563         _isMoving = false;
0564     }
0565 }
0566 
0567 double CircularArrowHandlerGraphicsItem::value()
0568 {
0569     if(_property) return _property->readVariant(_item).value<double>();
0570     else return 0;
0571 }
0572 
0573 void CircularArrowHandlerGraphicsItem::setValue(double value)
0574 {
0575     if(_property) {
0576         _worldModel->simulationPause();
0577         _worldModel->setProperty(_item, _property, QVariant::fromValue(value));
0578     }
0579 }
0580 
0581 /////////////////////////////////////////////////////////////////////////////////////////
0582 
0583 const StepCore::Vector2d OnHoverHandlerGraphicsItem::corners[4] = {
0584     StepCore::Vector2d(-0.5,-0.5), StepCore::Vector2d( 0.5,-0.5),
0585     StepCore::Vector2d(-0.5, 0.5), StepCore::Vector2d( 0.5, 0.5)
0586 };
0587 
0588 const StepCore::Vector2d OnHoverHandlerGraphicsItem::scorners[4] = {
0589     StepCore::Vector2d(0,-1), StepCore::Vector2d( 1,0),
0590     StepCore::Vector2d(0, 1), StepCore::Vector2d(-1,0)
0591 };
0592 
0593 OnHoverHandlerGraphicsItem::OnHoverHandlerGraphicsItem(StepCore::Item* item, WorldModel* worldModel,
0594                     QGraphicsItem* parent, const StepCore::MetaProperty* property,
0595                     const StepCore::MetaProperty* positionProperty, int vertexNum)
0596     : ArrowHandlerGraphicsItem(item, worldModel, parent, property, positionProperty)
0597     , _vertexNum(vertexNum)
0598 {
0599     _deleteTimer = new QTimer(this);
0600     _deleteTimer->setInterval(500);
0601     _deleteTimer->setSingleShot(true);
0602     _deleteTimerEnabled = false;
0603     setAcceptHoverEvents(true);
0604     connect(_deleteTimer, &QTimer::timeout, this, &QObject::deleteLater);
0605 }
0606 
0607 void OnHoverHandlerGraphicsItem::setDeleteTimerEnabled(bool enabled)
0608 {
0609     _deleteTimerEnabled = enabled;
0610     if(_deleteTimerEnabled && !isMouseOverItem()) _deleteTimer->start();
0611     else _deleteTimer->stop();
0612 }
0613 
0614 void OnHoverHandlerGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
0615 {
0616     if(_deleteTimerEnabled) _deleteTimer->stop();
0617     ArrowHandlerGraphicsItem::hoverEnterEvent(event);
0618 }
0619 
0620 void OnHoverHandlerGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
0621 {
0622     if(_deleteTimerEnabled) _deleteTimer->start();
0623     ArrowHandlerGraphicsItem::hoverLeaveEvent(event);
0624 }
0625 
0626 #include "moc_stepgraphicsitem.cpp"