1 /* This file is part of Step.
2    Copyright (C) 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
3 
4    Step is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    Step is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with Step; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18 
19 #ifndef STEP_WORLDSCENE_H
20 #define STEP_WORLDSCENE_H
21 
22 #include <QGraphicsScene>
23 #include <QGraphicsView>
24 #include <QList>
25 #include <QHash>
26 
27 #include "messageframe.h"
28 
29 class WorldModel;
30 //class ItemCreator;
31 
32 class QUrl;
33 class QModelIndex;
34 class QGraphicsItem;
35 class QItemSelection;
36 class StepGraphicsItem;
37 class WorldGraphicsView;
38 class ItemCreator;
39 class WorldSceneAxes;
40 
41 namespace StepCore {
42     class Item;
43     class MetaObject;
44 }
45 
46 /** \brief World scene class */
47 class WorldScene: public QGraphicsScene
48 {
49     Q_OBJECT
50 
51 public:
52     typedef QList<const StepCore::MetaObject*> SnapList;
53 
54     /** Flags for controlling item snapping behavior */
55     enum SnapFlag {
56         SnapOnCenter = 1,         ///< Snap to the center of the body
57         SnapSetPosition = 2,      ///< Set position property
58         SnapSetAngle = 4,         ///< Set angle property
59         SnapSetLocalPosition = 8, ///< Set localPosition property
60         SnapParticle = 256,         ///< Allow snapping to Particle
61         SnapRigidBody = 512        ///< Allow snapping to RigidBody
62     };
63     Q_DECLARE_FLAGS(SnapFlags, SnapFlag)
64 
65     /** Construct WorldScene */
66     explicit WorldScene(WorldModel* worldModel, QObject* parent = 0);
67     ~WorldScene();
68 
69     /** Get StepCore::Item by QGraphicsItem */
70     StepCore::Item* itemFromGraphics(const QGraphicsItem* graphicsItem) const;
71     /** Get StepGraphicsItem for given StepCore::Item */
72     StepGraphicsItem* graphicsFromItem(const StepCore::Item* item) const;
73 
74     /** Called by WorldView when view scale is updated */
75     void updateViewScale(); // Qt4.3 can help here
76     /** Get current view scale of the scene */
currentViewScale()77     double currentViewScale() { return _currentViewScale; }
78 
79     /** Calculate united bounding rect of all items
80      *  (not taking into account WorldSceneAxes */
81     QRectF calcItemsBoundingRect();
82 
83     /** Highlight item at given position
84      *  \param pos position
85      *  \param flags snap flags
86      *  \param moreTypes additional item types to snap */
87     StepCore::Item* snapHighlight(QPointF pos, SnapFlags flags, const SnapList* moreTypes = 0);
88 
89     /** Remove highlighting */
90     void snapClear();
91 
92     /** Attach item to another item at given position
93      *  \param pos position
94      *  \param flags snap flags
95      *  \param moreTypes additional item types to snap
96      *  \param movingState moving state of the item
97      *  \param item StepCore::Item to attach
98      *  \param num Num of the end to attach (or -1)
99      *
100      *  If movingState equals Started or Moving this function
101      *  will only highlight potential body to attach and leave current
102      *  body detaches. It movingState equals Finished the function
103      *  will actually attach the body.
104      *
105      *  This function sets "body" property of the item to snapped item
106      *  and "position" and/or "localPosition" property to the position
107      *  on snapped item. If num >=0 then QString::number(num) is added
108      *  to property names */
109     StepCore::Item* snapItem(QPointF pos, SnapFlags flags, const SnapList* moreTypes,
110                                   int movingState, StepCore::Item* item, int num = -1);
111 
112     /** Get associated WorldModel */
worldModel()113     WorldModel* worldModel() const { return _worldModel; }
114 
115     /** Check if scene has an active item creator */
116     bool hasItemCreator() const;
117 
118 public slots:
119     /** Begin adding new item. Creates appropriate ItemCreator */
120     void beginAddItem(const QString& name);
121 
122     /** Shows a message to the user
123      *  \param type message type
124      *  \param text message text
125      *  \param flags message flags
126      *  \return message id of the created message */
127     int showMessage(MessageFrame::Type type, const QString& text, MessageFrame::Flags flags = {}) {
128         return _messageFrame->showMessage(type, text, flags);
129     }
130     /** Changed existing message
131      *  \param id message id
132      *  \param type message type
133      *  \param text message text
134      *  \param flags message flags
135      *  \return new message id */
136     int changeMessage(int id, MessageFrame::Type type, const QString& text, MessageFrame::Flags flags = {}) {
137         return _messageFrame->changeMessage(id, type, text, flags);
138     }
139     /** Close message
140      *  \param id message id */
closeMessage(int id)141     void closeMessage(int id) { _messageFrame->closeMessage(id); }
142 
143     /** Reload application settings */
144     void settingsChanged();
145 
146 signals:
147     /** This signal is emitted when item creation is finished or canceled */
148     void endAddItem(const QString& name, bool success);
149     /** This signal is emitted when a link in the message is activated */
150     void linkActivated(const QUrl& url);
151 
152 protected slots:
153     void worldModelReset();
154     void worldDataChanged(bool dynamicOnly);
155     void worldCurrentChanged(const QModelIndex& current, const QModelIndex& previous);
156     void worldSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
157 
158     void worldRowsInserted(const QModelIndex& parent, int start, int end);
159     void worldRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);
160 
161     void messageLinkActivated(const QString& link);
162 
163     void snapUpdateToolTip();
164 
165 protected:
166     bool event(QEvent* event) override;
167     void mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) override;
168     void helpEvent(QGraphicsSceneHelpEvent *helpEvent) override;
169     //void contextMenuEvent(QGraphicsSceneContextMenuEvent* contextMenuEvent);
170 
171     void worldGetItemsRecursive(const QModelIndex& parent);
172 
173 protected:
174     WorldModel* _worldModel;
175     WorldGraphicsView* _worldView;
176     QHash<const StepCore::Item*, StepGraphicsItem*> _itemsHash;
177     double _currentViewScale;
178     ItemCreator* _itemCreator;
179     QRgb         _bgColor;
180 
181     MessageFrame      *_messageFrame;
182     WorldSceneAxes    *_sceneAxes;
183     StepGraphicsItem  *_snapItem;
184     QPointF            _snapPos;
185     QString            _snapToolTip;
186     QTimer*            _snapTimer;
187 
188     friend class WorldGraphicsView;
189 };
190 
191 /** \brief World view */
192 class WorldGraphicsView: public QGraphicsView
193 {
194     Q_OBJECT
195 
196 public:
197     WorldGraphicsView(WorldScene* worldScene, QWidget* parent);
198 
199 public slots:
200     void zoomIn();      ///< Zoom scene in
201     void zoomOut();     ///< Zoom scene out
202     void fitToPage();   ///< Ensure that all objects are visible
203     void actualSize();  ///< Set zoom to 100%
204 
205     /** Reload application settings */
206     void settingsChanged();
207 
208 protected slots:
209     void sceneRectChanged(const QRectF& rect);
210 
211 protected:
212     void mousePressEvent(QMouseEvent* e) override;
213     void mouseReleaseEvent(QMouseEvent* e) override;
214     void wheelEvent(QWheelEvent* e) override;
215     void scrollContentsBy(int dx, int dy) override;
216     void updateSceneRect();
217 
218     static const int SCENE_LENGTH = 2000;
219 
220     QRectF _sceneRect;
221 };
222 
223 Q_DECLARE_OPERATORS_FOR_FLAGS(WorldScene::SnapFlags)
224 
225 #endif
226 
227