~ubuntu-branches/ubuntu/trusty/step/trusty-proposed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/* This file is part of Step.
   Copyright (C) 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>

   Step is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   Step is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with Step; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef STEP_WORLDSCENE_H
#define STEP_WORLDSCENE_H

#include <QGraphicsScene>
#include <QGraphicsView>
#include <QList>
#include <QHash>

#include "messageframe.h"

class KUrl;
class WorldModel;
//class ItemCreator;
class QModelIndex;
class QGraphicsItem;
class QItemSelection;
class QVBoxLayout;
class QSignalMapper;
class WorldGraphicsItem;
class WorldGraphicsView;
class ItemCreator;
class WorldSceneAxes;

namespace StepCore {
    class Item;
    class MetaObject;
}

/** \brief World scene class */
class WorldScene: public QGraphicsScene
{
    Q_OBJECT

public:
    typedef QList<const StepCore::MetaObject*> SnapList;

    /** Flags for controlling item snapping behaviour */
    enum SnapFlag {
        SnapOnCenter = 1,         ///< Snap to the center of the body
        SnapSetPosition = 2,      ///< Set position property
        SnapSetAngle = 4,         ///< Set angle property
        SnapSetLocalPosition = 8, ///< Set localPosition property
        SnapParticle = 256,         ///< Allow snapping to Particle
        SnapRigidBody = 512        ///< Allow snapping to RigidBody
    };
    Q_DECLARE_FLAGS(SnapFlags, SnapFlag)

    /** Construct WorldScene */
    explicit WorldScene(WorldModel* worldModel, QObject* parent = 0);
    ~WorldScene();

    /** Get StepCore::Item by QGraphicsItem */
    StepCore::Item* itemFromGraphics(const QGraphicsItem* graphicsItem) const;
    /** Get WorldGraphicsItem for given StepCore::Item */
    WorldGraphicsItem* graphicsFromItem(const StepCore::Item* item) const;

    /** Called by WorldView when view scale is updated */
    void updateViewScale(); // Qt4.3 can help here
    /** Get current view scale of the scene */
    double currentViewScale() { return _currentViewScale; }

    /** Calculate united bounding rect of all items
     *  (not taking into account WorldSceneAxes */
    QRectF calcItemsBoundingRect();

    /** Highlight item at given position
     *  \param pos position
     *  \param flags snap flags
     *  \param moreTypes additional item types to snap */
    StepCore::Item* snapHighlight(QPointF pos, SnapFlags flags, const SnapList* moreTypes = 0);

    /** Remove highlighting */
    void snapClear();

    /** Attach item to another item at given position
     *  \param pos position
     *  \param flags snap flags
     *  \param moreTypes additional item types to snap
     *  \param movingState moving state of the item
     *  \param item StepCore::Item to attach
     *  \param num Num of the end to attach (or -1)
     *
     *  If movingState equals Started or Moving this function
     *  will only highlight potential body to attach and leave current
     *  body detaches. It movingState equals Finished the function
     *  will actually attach the body.
     *
     *  This function sets "body" property of the item to snapped item
     *  and "position" and/or "localPosition" property to the position
     *  on snapped item. If num >=0 then QString::number(num) is added
     *  to property names */
    StepCore::Item* snapItem(QPointF pos, SnapFlags flags, const SnapList* moreTypes,
                                  int movingState, StepCore::Item* item, int num = -1);

    /** Get associated WorldModel */
    WorldModel* worldModel() const { return _worldModel; }

    /** Check if scene has an active item creator */
    bool hasItemCreator() const;

public slots:
    /** Begin adding new item. Creates appropriate ItemCreator */
    void beginAddItem(const QString& name);

    /** Shows a message to the user
     *  \param type message type
     *  \param text message text
     *  \param flags message flags
     *  \return message id of the created message */
    int showMessage(MessageFrame::Type type, const QString& text, MessageFrame::Flags flags = 0) {
        return _messageFrame->showMessage(type, text, flags);
    }
    /** Changed existing message
     *  \param id message id
     *  \param type message type
     *  \param text message text
     *  \param flags message flags
     *  \return new message id */
    int changeMessage(int id, MessageFrame::Type type, const QString& text, MessageFrame::Flags flags = 0) {
        return _messageFrame->changeMessage(id, type, text, flags);
    }
    /** Close message
     *  \param id message id */
    void closeMessage(int id) { _messageFrame->closeMessage(id); }

    /** Reload application settings */
    void settingsChanged();
    
signals:
    /** This signal is emitted when item creation is finished or canceled */
    void endAddItem(const QString& name, bool success);
    /** This signal is emitted when a link in the message is activated */
    void linkActivated(const KUrl& url);

protected slots:
    void worldModelReset();
    void worldDataChanged(bool dynamicOnly);
    void worldCurrentChanged(const QModelIndex& current, const QModelIndex& previous);
    void worldSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
    
    void worldRowsInserted(const QModelIndex& parent, int start, int end);
    void worldRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);

    void messageLinkActivated(const QString& link);

    void snapUpdateToolTip();

protected:
    bool event(QEvent* event);
    void mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent);
    void helpEvent(QGraphicsSceneHelpEvent *helpEvent);
    //void contextMenuEvent(QGraphicsSceneContextMenuEvent* contextMenuEvent);

    void worldGetItemsRecursive(const QModelIndex& parent);

protected:
    WorldModel* _worldModel;
    WorldGraphicsView* _worldView;
    QHash<const StepCore::Item*, WorldGraphicsItem*> _itemsHash;
    double _currentViewScale;
    ItemCreator* _itemCreator;
    QRgb         _bgColor;

    MessageFrame*  _messageFrame;
    WorldSceneAxes* _sceneAxes;
    WorldGraphicsItem* _snapItem;
    QPointF            _snapPos;
    QString            _snapToolTip;
    QTimer*            _snapTimer;

    friend class WorldGraphicsView;
};

/** \brief World view */
class WorldGraphicsView: public QGraphicsView
{
    Q_OBJECT

public:
    WorldGraphicsView(WorldScene* worldScene, QWidget* parent);

public slots:
    void zoomIn();      ///< Zoom scene in
    void zoomOut();     ///< Zoom scene out
    void fitToPage();   ///< Ensure that all objects are visible
    void actualSize();  ///< Set zoom to 100%

    /** Reload application settings */
    void settingsChanged();

protected slots:
    void sceneRectChanged(const QRectF& rect);
    
protected:
    void mousePressEvent(QMouseEvent* e);
    void mouseReleaseEvent(QMouseEvent* e);
    void wheelEvent(QWheelEvent* e);
    void scrollContentsBy(int dx, int dy);
    void updateSceneRect();

    static const int SCENE_LENGTH = 2000;
    
    QRectF _sceneRect;
};

Q_DECLARE_OPERATORS_FOR_FLAGS(WorldScene::SnapFlags)

#endif