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

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 #ifndef STEP_STEPGRAPHICSITEM_H
0009 #define STEP_STEPGRAPHICSITEM_H
0010 
0011 //#include "worldscene.h"
0012 
0013 #include <stepcore/vector.h>
0014 #include <QColor>
0015 #include <QGraphicsItem>
0016 #include <QPointer>
0017 #include <QRectF>
0018 
0019 namespace StepCore {
0020     class Object;
0021     class Item;
0022     class MetaProperty;
0023 }
0024 class WorldModel;
0025 //class WorldScene;
0026 class QTimer;
0027 
0028 /////////////////////////////////////////////////////////////////////////////////////////
0029 
0030 class OnHoverHandlerGraphicsItem;
0031 
0032 /** \brief Base class for all the graphics items on the scene.
0033  *
0034  * This class provides interface for WorldScene and
0035  * some common functionality to simplify subclassing.
0036  */
0037 class StepGraphicsItem : public QGraphicsItem
0038 {
0039 public:
0040     /** Flags describing movingState when
0041      *  moving item with the mouse */
0042     enum MovingState { Started, Moving, Finished };
0043 
0044     /** Constructs StepGraphicsItem */
0045     StepGraphicsItem(StepCore::Item* item, WorldModel* worldModel, QGraphicsItem* parent = nullptr);
0046 
0047     /** Get StepCore::Item which is represented by this graphicsItem */
0048     StepCore::Item* item() const { return _item; }
0049 
0050     /** Get item bounding rect. Default implementation returns
0051      *  value set by setBoundingRect function */
0052     QRectF boundingRect() const override { return _boundingRect; }
0053 
0054     /** Set current bounding rect. Should be called by subclass. */
0055     void setBoundingRect(const QRectF& rect) { _boundingRect = rect; }
0056 
0057     /** Virtual function which is called when view scale is changed */
0058     virtual void viewScaleChanged();
0059 
0060     /** Virtual function which is called when:
0061      *  - item selection state changed
0062      *  - item mouse hover state changed
0063      */
0064     virtual void stateChanged();
0065 
0066     /** Virtual function which is called when something in StepCore::World was changed
0067      *  \param dynamicOnly Indicated whether only dynamic variables was changed
0068      *  \note Dynamic variables are variables that can change during simulation,
0069      *        non-dynamic variables can change only by user action
0070      */
0071     virtual void worldDataChanged(bool dynamicOnly);
0072 
0073     /** Virtual function to paint the item. Default implementation
0074      *  draws boundingRect() in grey color */
0075     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
0076 
0077     /** Get item highlight state */
0078     bool isItemHighlighted() { return _isHighlighted; }
0079     /** Set item highlight state */
0080     void setItemHighlighted(bool highlighted) {
0081         _isHighlighted = highlighted; update();
0082     }
0083 
0084     /** Get selection state of the item. This function reflects selection state of
0085      *  StepCore::Item and differs from QGraphicsItem::isSelected when selection state
0086      *  of QGraphicsItem was not yet updated (for example in stateChanged() function) */
0087     bool isItemSelected() { return _isSelected; }
0088     /** Return true if item is hovered by the mouse */
0089     bool isMouseOverItem() { return _isMouseOverItem; }
0090 
0091     /** Converts QPointF to StepCore::Vector2d */
0092     static StepCore::Vector2d pointToVector(const QPointF& point) {
0093         return StepCore::Vector2d(point.x(), point.y());
0094     }
0095     /** Converts StepCore::Vector2d to QPointF */
0096     static QPointF vectorToPoint(const StepCore::Vector2d& vector) {
0097         return QPointF(vector[0], vector[1]);
0098     }
0099 
0100 protected:
0101     /** Virtual function which is called when item is moved by the mouse. Default implementation
0102      *  tries to set "position" property of _item */
0103     virtual void mouseSetPos(const QPointF& pos, const QPointF& diff, MovingState movingState);
0104 
0105     /** Returns current view scale of the scene */
0106     double currentViewScale() const;
0107 
0108     /** Returns highlighted copy of the color */
0109     QColor highlightColor(const QColor& color);
0110 
0111     ///* Draw handler item */
0112     //void drawHandler(QPainter* painter, const StepCore::Vector2d& v);
0113 
0114     /** Draw an arrow starting at r and ending at v */
0115     void drawArrow(QPainter* painter, const StepCore::Vector2d& r,
0116                                         const StepCore::Vector2d& v);
0117     /** Draw an arrow starting at (0,0) and ending at v */
0118     void drawArrow(QPainter* painter, const StepCore::Vector2d& v);
0119 
0120     /** Draw circular arrow with the center at r and with given radius and angle */
0121     void drawCircularArrow(QPainter* painter, const StepCore::Vector2d& r,
0122                                         double angle, double radius);
0123     /** Draw circular arrow with the center at (0,0) and with given radius and angle */
0124     void drawCircularArrow(QPainter* painter, double angle, double radius);
0125 
0126     /** Set to true if the item should be moved alone (without other selected items) */
0127     void setExclusiveMoving(bool value) { _exclusiveMoving = value; }
0128 
0129     /** Set custom test for undo command for moving item. Works only if exclusiveMoving is true */
0130     void setExclusiveMovingMessage(const QString& message) { _exclusiveMovingMessage = message; }
0131 
0132     /** Called when graphicsitem is changed */
0133     QVariant itemChange(GraphicsItemChange change, const QVariant& value) override;
0134 
0135     /** Get vertex handler enabled status */
0136     bool isOnHoverHandlerEnabled() const { return _onHoverHandlerEnabled; }
0137 
0138     /** Set to true in order to enable on-hover handler.
0139      *  \note You should also call setAcceptHoverEvents(true) in order
0140      *  for on-hover handler to work */
0141     void setOnHoverHandlerEnabled(bool enabled);
0142 
0143     /** Virtual function which is called to create on-hover handler for given point.
0144      *  If the handler is the same as already-existing just return _onHoverHandler.
0145      *  If no handler it required for given point just return NULL */
0146     virtual OnHoverHandlerGraphicsItem* createOnHoverHandler(const QPointF&) { return nullptr; }
0147 
0148 protected:
0149     StepCore::Item* _item;
0150     WorldModel* _worldModel;
0151 
0152     QRectF  _boundingRect;
0153     QString _exclusiveMovingMessage;
0154     bool    _exclusiveMoving;
0155     bool    _onHoverHandlerEnabled;
0156 
0157     bool    _isHighlighted; 
0158     bool    _isMouseOverItem;
0159     bool    _isSelected;
0160     bool    _isMoving;
0161 
0162     QPointer<OnHoverHandlerGraphicsItem> _onHoverHandler;
0163     bool _onHoverHandlerTimer;
0164 
0165     void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
0166     void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
0167     void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;
0168 
0169     void hoverEnterEvent(QGraphicsSceneHoverEvent* event) override;
0170     void hoverMoveEvent(QGraphicsSceneHoverEvent* event) override;
0171     void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override;
0172 
0173     void contextMenuEvent(QGraphicsSceneContextMenuEvent* event) override;
0174 
0175 protected:
0176     static const QColor SELECTION_COLOR;     ///< Default color for selection rectangle
0177     static const int SELECTION_MARGIN = 4;   ///< Default distance from object to selection rectangle
0178     static const int ARROW_STROKE = 6;       ///< Default size of an arrow stroke
0179     static const int CIRCULAR_ARROW_STROKE = 6; ///< Default size of circular arrow stroke
0180 
0181     static const int HANDLER_SIZE = 6;          ///< Default size of the handler
0182     static const int HANDLER_SNAP_SIZE = 12;    ///< Handler snapping radius
0183 
0184     static const int ANGLE_HANDLER_RADIUS = 15;     ///< Default radius of the angle handler for RigidBody
0185     static const int ANGULAR_VELOCITY_RADIUS = 30;  ///< Default radius of the angularVelocity handler for RigidBody
0186     static const int ANGULAR_ACCELERATION_RADIUS = 34; ///< Default radius of the angularAcceleration handler
0187 
0188     static const int REGION_ZVALUE = 100;   ///< Default ZValue for regions
0189     static const int BODY_ZVALUE = 200;     ///< Default ZValue for bodies
0190     static const int FORCE_ZVALUE = 300;    ///< Default ZValue for forces
0191     static const int JOINT_ZVALUE = 400;    ///< Default ZValue for joints
0192     static const int HANDLER_ZVALUE = 800;  ///< Default ZValue for handlers
0193 
0194     static const int COLOR_HIGHLIGHT_AMOUNT = 30; ///< Highlight amount (in percent for value component)
0195 };
0196 
0197 /////////////////////////////////////////////////////////////////////////////////////////
0198 
0199 /** \brief Handler item that controls vector property
0200  */
0201 class ArrowHandlerGraphicsItem : public StepGraphicsItem
0202 {
0203 public:
0204     /** Construct ArrowHandlerGraphicsItem.
0205      *  \param item StepCore::Item to control
0206      *  \param worldModel associated worldModel
0207      *  \param parent parent StepGraphicsItem
0208      *  \param property Property to control
0209      *  \param positionProperty Origin of the vector described by property or NULL
0210      */
0211     ArrowHandlerGraphicsItem(StepCore::Item* item, WorldModel* worldModel,
0212                         QGraphicsItem* parent, const StepCore::MetaProperty* property,
0213                         const StepCore::MetaProperty* positionProperty = nullptr);
0214 
0215     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
0216 
0217     void viewScaleChanged() override;
0218     void worldDataChanged(bool) override;
0219 
0220 protected:
0221     /** Virtual function which is called to get current vector value.
0222      *  Default implementation returns property + positionProperty */
0223     virtual StepCore::Vector2d value();
0224     /** Virtual function which is called to set current new vector value.
0225      *  Default implementation sets property = value - positionProperty */
0226     virtual void setValue(const StepCore::Vector2d& value);
0227 
0228     void mouseSetPos(const QPointF& pos, const QPointF& diff, MovingState movingState) override;
0229     QVariant itemChange(GraphicsItemChange change, const QVariant& value) override;
0230     const StepCore::MetaProperty* _property;
0231     const StepCore::MetaProperty* _positionProperty;
0232 };
0233 
0234 /////////////////////////////////////////////////////////////////////////////////////////
0235 
0236 /** \brief Handler item that controls angle property
0237  */
0238 class CircularArrowHandlerGraphicsItem : public StepGraphicsItem
0239 {
0240 public:
0241     /** Construct CircularArrowHandlerGraphicsItem.
0242      *  \param item StepCore::Item to control
0243      *  \param worldModel associated worldModel
0244      *  \param parent parent StepGraphicsItem
0245      *  \param radius radius of the arrow on the screen
0246      *  \param property Property to control
0247      *  \param positionProperty Position of the center of the circle
0248      */
0249     CircularArrowHandlerGraphicsItem(StepCore::Item* item, WorldModel* worldModel,
0250                         QGraphicsItem* parent, double radius, const StepCore::MetaProperty* property,
0251                         const StepCore::MetaProperty* positionProperty = nullptr);
0252 
0253     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
0254 
0255     void viewScaleChanged() override;
0256     void worldDataChanged(bool) override;
0257 
0258 protected:
0259     /** Virtual function which is called to get current vector value.
0260      *  Default implementation reads the value pointed by property */
0261     virtual double value();
0262     /** Virtual function which is called to set current new vector value.
0263      *  Default implementation sets the value pointed by property */
0264     virtual void setValue(double value);
0265 
0266     QVariant itemChange(GraphicsItemChange change, const QVariant& value) override;
0267     void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
0268     void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
0269     const StepCore::MetaProperty* _property;
0270     const StepCore::MetaProperty* _positionProperty;
0271     double _radius;
0272 };
0273 
0274 /////////////////////////////////////////////////////////////////////////////////////////
0275 
0276 /** \brief Base class for handler that exists only on mouse hover */
0277 class OnHoverHandlerGraphicsItem : public QObject, public ArrowHandlerGraphicsItem
0278 {
0279     Q_OBJECT
0280 
0281 public:
0282     OnHoverHandlerGraphicsItem(StepCore::Item* item, WorldModel* worldModel,
0283                     QGraphicsItem* parent, const StepCore::MetaProperty* property,
0284                     const StepCore::MetaProperty* positionProperty = nullptr,
0285                     int vertexNum = 0);
0286 
0287     void setDeleteTimerEnabled(bool enabled);
0288     bool isDeleteTimerEnabled() const { return _deleteTimerEnabled; }
0289 
0290     int vertexNum() const { return _vertexNum; }
0291     void setVertexNum(int vertexNum) { _vertexNum = vertexNum; }
0292 
0293     static const StepCore::Vector2d corners[4];
0294     static const StepCore::Vector2d scorners[4];
0295 
0296 protected:
0297     void hoverEnterEvent(QGraphicsSceneHoverEvent* event) override;
0298     void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override;
0299 
0300     int _vertexNum;
0301     QTimer* _deleteTimer;
0302     bool _deleteTimerEnabled;
0303 };
0304 
0305 #endif
0306