File indexing completed on 2024-04-28 07:39:43

0001 /*.
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef STEP_WORLDSCENE_H
0008 #define STEP_WORLDSCENE_H
0009 
0010 #include <QGraphicsScene>
0011 #include <QGraphicsView>
0012 #include <QList>
0013 #include <QHash>
0014 
0015 #include "messageframe.h"
0016 
0017 class WorldModel;
0018 //class ItemCreator;
0019 
0020 class QUrl;
0021 class QModelIndex;
0022 class QGraphicsItem;
0023 class QItemSelection;
0024 class StepGraphicsItem;
0025 class WorldGraphicsView;
0026 class ItemCreator;
0027 class WorldSceneAxes;
0028 
0029 namespace StepCore {
0030     class Item;
0031     class MetaObject;
0032 }
0033 
0034 /** \brief World scene class */
0035 class WorldScene: public QGraphicsScene
0036 {
0037     Q_OBJECT
0038 
0039 public:
0040     typedef QList<const StepCore::MetaObject*> SnapList;
0041 
0042     /** Flags for controlling item snapping behavior */
0043     enum SnapFlag {
0044         SnapOnCenter = 1,         ///< Snap to the center of the body
0045         SnapSetPosition = 2,      ///< Set position property
0046         SnapSetAngle = 4,         ///< Set angle property
0047         SnapSetLocalPosition = 8, ///< Set localPosition property
0048         SnapParticle = 256,         ///< Allow snapping to Particle
0049         SnapRigidBody = 512        ///< Allow snapping to RigidBody
0050     };
0051     Q_DECLARE_FLAGS(SnapFlags, SnapFlag)
0052 
0053     /** Construct WorldScene */
0054     explicit WorldScene(WorldModel* worldModel, QObject* parent = nullptr);
0055     ~WorldScene();
0056 
0057     /** Get StepCore::Item by QGraphicsItem */
0058     StepCore::Item* itemFromGraphics(const QGraphicsItem* graphicsItem) const;
0059     /** Get StepGraphicsItem for given StepCore::Item */
0060     StepGraphicsItem* graphicsFromItem(const StepCore::Item* item) const;
0061 
0062     /** Called by WorldView when view scale is updated */
0063     void updateViewScale(); // Qt4.3 can help here
0064     /** Get current view scale of the scene */
0065     double currentViewScale() { return _currentViewScale; }
0066 
0067     /** Calculate united bounding rect of all items
0068      *  (not taking into account WorldSceneAxes */
0069     QRectF calcItemsBoundingRect();
0070 
0071     /** Highlight item at given position
0072      *  \param pos position
0073      *  \param flags snap flags
0074      *  \param moreTypes additional item types to snap */
0075     StepCore::Item* snapHighlight(QPointF pos, SnapFlags flags, const SnapList* moreTypes = nullptr);
0076 
0077     /** Remove highlighting */
0078     void snapClear();
0079 
0080     /** Attach item to another item at given position
0081      *  \param pos position
0082      *  \param flags snap flags
0083      *  \param moreTypes additional item types to snap
0084      *  \param movingState moving state of the item
0085      *  \param item StepCore::Item to attach
0086      *  \param num Num of the end to attach (or -1)
0087      *
0088      *  If movingState equals Started or Moving this function
0089      *  will only highlight potential body to attach and leave current
0090      *  body detaches. It movingState equals Finished the function
0091      *  will actually attach the body.
0092      *
0093      *  This function sets "body" property of the item to snapped item
0094      *  and "position" and/or "localPosition" property to the position
0095      *  on snapped item. If num >=0 then QString::number(num) is added
0096      *  to property names */
0097     StepCore::Item* snapItem(QPointF pos, SnapFlags flags, const SnapList* moreTypes,
0098                                   int movingState, StepCore::Item* item, int num = -1);
0099 
0100     /** Get associated WorldModel */
0101     WorldModel* worldModel() const { return _worldModel; }
0102 
0103     /** Check if scene has an active item creator */
0104     bool hasItemCreator() const;
0105 
0106 public slots:
0107     /** Begin adding new item. Creates appropriate ItemCreator */
0108     void beginAddItem(const QString& name);
0109 
0110     /** Shows a message to the user
0111      *  \param type message type
0112      *  \param text message text
0113      *  \param flags message flags
0114      *  \return message id of the created message */
0115     int showMessage(MessageFrame::Type type, const QString& text, MessageFrame::Flags flags = {}) {
0116         return _messageFrame->showMessage(type, text, flags);
0117     }
0118     /** Changed existing message
0119      *  \param id message id
0120      *  \param type message type
0121      *  \param text message text
0122      *  \param flags message flags
0123      *  \return new message id */
0124     int changeMessage(int id, MessageFrame::Type type, const QString& text, MessageFrame::Flags flags = {}) {
0125         return _messageFrame->changeMessage(id, type, text, flags);
0126     }
0127     /** Close message
0128      *  \param id message id */
0129     void closeMessage(int id) { _messageFrame->closeMessage(id); }
0130 
0131     /** Reload application settings */
0132     void settingsChanged();
0133     
0134 signals:
0135     /** This signal is emitted when item creation is finished or canceled */
0136     void endAddItem(const QString& name, bool success);
0137     /** This signal is emitted when a link in the message is activated */
0138     void linkActivated(const QUrl& url);
0139 
0140 protected slots:
0141     void worldModelReset();
0142     void worldDataChanged(bool dynamicOnly);
0143     void worldCurrentChanged(const QModelIndex& current, const QModelIndex& previous);
0144     void worldSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
0145     
0146     void worldRowsInserted(const QModelIndex& parent, int start, int end);
0147     void worldRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);
0148 
0149     void messageLinkActivated(const QString& link);
0150 
0151     void snapUpdateToolTip();
0152 
0153 protected:
0154     bool event(QEvent* event) override;
0155     void mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) override;
0156     void helpEvent(QGraphicsSceneHelpEvent *helpEvent) override;
0157     //void contextMenuEvent(QGraphicsSceneContextMenuEvent* contextMenuEvent);
0158 
0159     void worldGetItemsRecursive(const QModelIndex& parent);
0160 
0161 protected:
0162     WorldModel* _worldModel;
0163     WorldGraphicsView* _worldView;
0164     QHash<const StepCore::Item*, StepGraphicsItem*> _itemsHash;
0165     double _currentViewScale;
0166     ItemCreator* _itemCreator;
0167     QRgb         _bgColor;
0168 
0169     MessageFrame      *_messageFrame;
0170     WorldSceneAxes    *_sceneAxes;
0171     StepGraphicsItem  *_snapItem;
0172     QPointF            _snapPos;
0173     QString            _snapToolTip;
0174     QTimer*            _snapTimer;
0175 
0176     friend class WorldGraphicsView;
0177 };
0178 
0179 /** \brief World view */
0180 class WorldGraphicsView: public QGraphicsView
0181 {
0182     Q_OBJECT
0183 
0184 public:
0185     WorldGraphicsView(WorldScene* worldScene, QWidget* parent);
0186 
0187 public slots:
0188     void zoomIn();      ///< Zoom scene in
0189     void zoomOut();     ///< Zoom scene out
0190     void fitToPage();   ///< Ensure that all objects are visible
0191     void actualSize();  ///< Set zoom to 100%
0192 
0193     /** Reload application settings */
0194     void settingsChanged();
0195 
0196 protected slots:
0197     void sceneRectChanged(const QRectF& rect);
0198     
0199 protected:
0200     void mousePressEvent(QMouseEvent* e) override;
0201     void mouseReleaseEvent(QMouseEvent* e) override;
0202     void wheelEvent(QWheelEvent* e) override;
0203     void scrollContentsBy(int dx, int dy) override;
0204     void updateSceneRect();
0205 
0206     static const int SCENE_LENGTH = 2000;
0207     
0208     QRectF _sceneRect;
0209 };
0210 
0211 Q_DECLARE_OPERATORS_FOR_FLAGS(WorldScene::SnapFlags)
0212 
0213 #endif
0214