Warning, file /education/step/step/worldscene.cc was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*.
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "worldscene.h"
0008 
0009 #ifdef _WIN32
0010 #include <windows.h>
0011 #endif
0012 
0013 #include "settings.h"
0014 
0015 #include "arrow.h"
0016 #include "worldmodel.h"
0017 #include "worldfactory.h"
0018 #include "stepgraphicsitem.h"
0019 #include "worldgraphics.h"
0020 
0021 #include <stepcore/world.h>
0022 #include <stepcore/particle.h>
0023 #include <stepcore/rigidbody.h>
0024 
0025 #include <QCoreApplication>
0026 #include <QOpenGLWidget>
0027 #include <QGraphicsItem>
0028 #include <QGraphicsSceneMouseEvent>
0029 #include <QItemSelectionModel>
0030 #include <QPainter>
0031 #include <QScrollBar>
0032 #include <QTimer>
0033 #include <QToolTip>
0034 #include <QUrl>
0035 #include <QWheelEvent>
0036 
0037 #include <KLocalizedString>
0038 
0039 class WorldSceneAxes: public QGraphicsItem
0040 {
0041 public:
0042     WorldSceneAxes(QGraphicsItem* parent = nullptr, QGraphicsScene* scene = nullptr);
0043     QRectF boundingRect() const override;
0044     QPainterPath shape() const override;
0045     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
0046     void viewScaleChanged();
0047 
0048 protected:
0049     QRectF _boundingRect;
0050     double _viewScale;
0051     static const int LENGTH = 100;
0052     static const int LENGTHT = 100;
0053     static const int LENGTH1 = 10;
0054     static const int ARROW_STROKE = 6;
0055 };
0056 
0057 WorldSceneAxes::WorldSceneAxes(QGraphicsItem* parent, QGraphicsScene* scene)
0058     : QGraphicsItem(parent),
0059     _boundingRect(-LENGTH, -LENGTH, LENGTH+LENGTH, LENGTH+LENGTH)
0060 {
0061     _viewScale = 1;
0062     setZValue(-100);
0063     if (scene)
0064       scene->addItem(this);
0065 }
0066 
0067 QRectF WorldSceneAxes::boundingRect() const
0068 {
0069     return _boundingRect;
0070 }
0071 
0072 QPainterPath WorldSceneAxes::shape() const
0073 {
0074     return QPainterPath();
0075 }
0076 
0077 void WorldSceneAxes::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
0078 {
0079     QPen pen(Qt::gray, 2);
0080     pen.setCosmetic(true);
0081     painter->setPen(pen);//, Qt::DotLine, Qt::SquareCap, Qt::RoundJoin));
0082     //painter->drawLine(QLineF(0, -LENGTH, 0, LENGTH));
0083     //painter->drawLine(QLineF(-LENGTH, 0, LENGTH, 0));
0084     Arrow arrow(0, LENGTH, 0, -LENGTH, 8);
0085     arrow.draw(painter);
0086     Arrow arrow2(-LENGTH, 0, LENGTH, 0, 8);
0087     arrow2.draw(painter);
0088     //painter->drawLine(QLineF(0, -LENGTH, 0, LENGTH));
0089     //painter->drawLine(QLineF(-LENGTH, 0, LENGTH, 0));
0090     //painter->drawLine(QLineF(-2, -LENGTHT, 2, -LENGTHT));
0091     //painter->drawLine(QLineF(LENGTHT, -2, LENGTHT, 2));
0092 
0093     //painter->drawLine(QLineF(0, -LENGTH, -0.5*ARROW_STROKE, -LENGTH+0.866*ARROW_STROKE ));
0094     //painter->drawLine(QLineF(0, -LENGTH, +0.5*ARROW_STROKE, -LENGTH+0.866*ARROW_STROKE ));
0095     //painter->drawLine(QLineF(LENGTH, 0, LENGTH-0.866*ARROW_STROKE, -0.5*ARROW_STROKE ));
0096     //painter->drawLine(QLineF(LENGTH, 0, LENGTH-0.866*ARROW_STROKE, +0.5*ARROW_STROKE ));
0097 
0098     painter->drawText(QRectF(-LENGTH - 6, 6, LENGTH, LENGTH),
0099                         Qt::AlignRight | Qt::AlignTop,
0100                         QStringLiteral("%1,%2").arg( pos().x(), 0, 'g', 3 ).arg( pos().y(), 0, 'g', 3 ));
0101     painter->drawText(QRectF(6, -LENGTH, LENGTH - 6, LENGTH - 6),
0102             Qt::AlignLeft | Qt::AlignTop, QString::number( pos().y() + LENGTH/_viewScale, 'g', 3 ));
0103     painter->drawText(QRectF(6, -LENGTH, LENGTH - 6, LENGTH - 6),
0104             Qt::AlignRight | Qt::AlignBottom, QString::number( pos().x() + LENGTH/_viewScale, 'g', 3 ));
0105 
0106     //painter->drawText(QRectF(ARROW_STROKE, -LENGTHT-50, LENGTHT, 100), Qt::AlignLeft | Qt::AlignVCenter,
0107     //                        QString::number( pos().y() + LENGTHT/_viewScale, 'g', 3 ));
0108     //painter->drawText(QRectF(LENGTHT-50, -LENGTHT, 100, LENGTHT), Qt::AlignHCenter | Qt::AlignBottom,
0109     //                        QString::number( pos().x() + LENGTHT/_viewScale, 'g', 3 ));
0110 }
0111 
0112 void WorldSceneAxes::viewScaleChanged()
0113 {
0114     prepareGeometryChange();
0115     _viewScale = static_cast<WorldScene*>(scene())->currentViewScale();
0116     setTransform(QTransform::fromScale(1/_viewScale, -1/_viewScale), false);
0117 }
0118 
0119 WorldScene::WorldScene(WorldModel* worldModel, QObject* parent)
0120     : QGraphicsScene(parent), _worldModel(worldModel), _worldView(nullptr),
0121         _currentViewScale(1), _itemCreator(nullptr), _bgColor(0),
0122         _sceneAxes(nullptr), _snapItem(nullptr)
0123 {
0124     #ifdef __GNUC__
0125     #warning TODO: measure what index method is faster
0126     #endif
0127 
0128     // Alternative index method is BspTreeIndex
0129     setItemIndexMethod(NoIndex);
0130     //XXX
0131     //setct(-200,-200,400,400);
0132     setSceneRect(-20, -20, 40, 40);
0133 
0134     _messageFrame = new MessageFrame();
0135     _snapTimer = new QTimer(this);
0136     _snapTimer->setInterval(0);
0137     _snapTimer->setSingleShot(true);
0138 
0139     worldModelReset();
0140 
0141     connect(_worldModel, &QAbstractItemModel::modelReset, this, &WorldScene::worldModelReset);
0142     connect(_worldModel, &WorldModel::worldDataChanged, this, &WorldScene::worldDataChanged);
0143     connect(_worldModel->selectionModel(), &QItemSelectionModel::currentChanged,
0144                                   this, &WorldScene::worldCurrentChanged);
0145     connect(_worldModel->selectionModel(), &QItemSelectionModel::selectionChanged,
0146                                   this, &WorldScene::worldSelectionChanged);
0147     connect(_worldModel, &QAbstractItemModel::rowsInserted,
0148                 this, &WorldScene::worldRowsInserted);
0149     connect(_worldModel, &QAbstractItemModel::rowsAboutToBeRemoved,
0150                          this, &WorldScene::worldRowsAboutToBeRemoved);
0151 
0152     connect(_messageFrame, &MessageFrame::linkActivated,
0153                 this, &WorldScene::messageLinkActivated);
0154     connect(_snapTimer, &QTimer::timeout, this, &WorldScene::snapUpdateToolTip);
0155 }
0156 
0157 WorldScene::~WorldScene()
0158 {
0159 }
0160 
0161 StepCore::Item* WorldScene::itemFromGraphics(const QGraphicsItem* graphicsItem) const
0162 {
0163     const StepGraphicsItem* worldGraphicsItem =
0164             dynamic_cast<const StepGraphicsItem*>(graphicsItem);
0165     if(worldGraphicsItem != nullptr) return worldGraphicsItem->item();
0166     else return nullptr;
0167 }
0168 
0169 StepGraphicsItem* WorldScene::graphicsFromItem(const StepCore::Item* item) const
0170 {
0171     return _itemsHash.value(item, NULL);
0172 }
0173 
0174 void WorldScene::beginAddItem(const QString& name)
0175 {
0176     //_currentCreator = name;
0177     if(_itemCreator) {
0178         _itemCreator->abort();
0179         emit endAddItem(_itemCreator->className(), _itemCreator->item() != nullptr);
0180         delete _itemCreator;
0181     }
0182     if(name == QLatin1String("Pointer")) {
0183         _itemCreator = nullptr;
0184     } else {
0185         _itemCreator = _worldModel->worldFactory()->newItemCreator(name, _worldModel, this);
0186         Q_ASSERT(_itemCreator != nullptr);
0187         _itemCreator->start();
0188     }
0189 }
0190 
0191 bool WorldScene::event(QEvent* event)
0192 {
0193     //qDebug("event, _currentCreator = %s", _currentCreator.toAscii().constData());
0194     /*if(!_currentCreator.isEmpty()) {
0195         if(_worldModel->worldFactory()->graphicsCreateItem(_currentCreator, _worldModel,
0196                             this, event)) {
0197             emit endAddItem(_currentCreator, true);
0198             _currentCreator.clear();
0199         }
0200         if(event->isAccepted()) return true;
0201     }*/
0202     if(_itemCreator) {
0203         bool handled = _itemCreator->sceneEvent(event);
0204         if(_itemCreator->finished()) {
0205             emit endAddItem(_itemCreator->className(), _itemCreator->item() != nullptr);
0206             // ~ItemCreator() will indirectly call this method, thus we must set
0207             // the pointer to NULL before deleting the ItemCreator.
0208             ItemCreator* itemCreator = _itemCreator;
0209             _itemCreator = nullptr;
0210             delete itemCreator;
0211         }
0212         if(handled) {
0213             event->accept();
0214             return true;
0215         }
0216     }
0217     return QGraphicsScene::event(event);
0218 }
0219 
0220 void WorldScene::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent)
0221 {
0222     if(itemAt(mouseEvent->scenePos(), QTransform()) == nullptr) {
0223         // XXX: how to easily select World ?
0224         //_worldModel->selectionModel()->clearSelection();
0225         _worldModel->selectionModel()->setCurrentIndex(_worldModel->worldIndex(), QItemSelectionModel::Clear);
0226     }
0227 
0228     QGraphicsScene::mousePressEvent(mouseEvent);
0229 }
0230 
0231 void WorldScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
0232 {
0233     helpEvent->accept();
0234     
0235     if(_snapItem || _snapTimer->isActive()) return;
0236 
0237     QString text;
0238 
0239     QList<StepCore::Item*> activeItems;
0240     foreach(QGraphicsItem* it, items(helpEvent->scenePos())) {
0241         if(it->parentItem()) continue;
0242         StepCore::Item* item = itemFromGraphics(it);
0243         if(item) activeItems << item;
0244     }
0245 
0246     int count = activeItems.count();
0247     if(count > 1) { //XXX
0248         text = QStringLiteral("<nobr><h4><u>%1</u></h4></nobr>").arg(i18n("Objects under mouse:"));
0249         for(int i=0; i<qMin<int>(count,10); ++i)
0250             text += QStringLiteral("<br /><nobr>%1</nobr>")
0251                         .arg(_worldModel->objectIndex(activeItems[i]).data(Qt::DisplayRole).toString());
0252         if(count > 10)
0253             text += QStringLiteral("<br /><nobr>%1</nobr>").arg(i18np("... (1 more item)", "... (%1 more items)", count - 10));
0254     } else {
0255         for(int i=0; i<count; ++i)
0256             text += _worldModel->objectIndex(activeItems[i]).data(Qt::ToolTipRole).toString();
0257     }
0258 
0259     Q_ASSERT(helpEvent->widget());
0260     QToolTip::showText(helpEvent->screenPos(), text, helpEvent->widget(), QRect());
0261 }
0262 
0263 void WorldScene::worldModelReset()
0264 {
0265     /* Clear */
0266     while(!items().isEmpty()) {
0267         QGraphicsItem* item = items()[0];
0268         removeItem(item);
0269         delete item;
0270     }
0271     _itemsHash.clear();
0272     _sceneAxes = nullptr;
0273 
0274     /* Background */
0275     if(_bgColor != _worldModel->world()->color()) {
0276         _bgColor = _worldModel->world()->color();
0277         if(_bgColor == 0) setBackgroundBrush(Qt::NoBrush);
0278         else setBackgroundBrush(QBrush(QColor::fromRgba(_bgColor)));
0279     }
0280 
0281     /* Axes */
0282     if(Settings::showAxes()) {
0283         _sceneAxes = new WorldSceneAxes();
0284         addItem(_sceneAxes);
0285         _sceneAxes->viewScaleChanged();
0286     }
0287 
0288     /* Check for new items */
0289     worldGetItemsRecursive(_worldModel->worldIndex());
0290 
0291     update();
0292 }
0293 
0294 void WorldScene::worldGetItemsRecursive(const QModelIndex& parent)
0295 {
0296     for(int i=0; i<_worldModel->rowCount(parent); ++i) {
0297         worldRowsInserted(parent, i, i);
0298         worldGetItemsRecursive(_worldModel->index(i, 0, parent));
0299     }
0300 }
0301 
0302 void WorldScene::worldRowsInserted(const QModelIndex& parent, int start, int end)
0303 {
0304     for(int i=start; i<=end; ++i) {
0305         QModelIndex index = _worldModel->index(i, 0, parent);
0306 
0307         StepCore::Item* item = _worldModel->item(index);
0308         if(!item) continue;
0309         StepGraphicsItem* graphicsItem =
0310             _worldModel->worldFactory()->newGraphicsItem(item, _worldModel);
0311         if(!graphicsItem) continue;
0312 
0313         _itemsHash.insert(item, graphicsItem);
0314         addItem(graphicsItem);
0315         graphicsItem->viewScaleChanged();
0316         graphicsItem->worldDataChanged(false);
0317         foreach(QGraphicsItem *item, items()) {
0318             if(graphicsItem->isAncestorOf(item)) {
0319                 StepGraphicsItem* gItem = dynamic_cast<StepGraphicsItem*>(item);
0320                 if(gItem) gItem->viewScaleChanged();
0321             }
0322         }
0323 
0324         worldGetItemsRecursive(index);
0325     }
0326 }
0327 
0328 void WorldScene::worldRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end)
0329 {
0330     for(int i=start; i<=end; ++i) {
0331         QModelIndex index = _worldModel->index(i, 0, parent);
0332         
0333         int childCount = _worldModel->rowCount(index);
0334         if(childCount > 0) worldRowsAboutToBeRemoved(index, 0, childCount-1);
0335 
0336         QGraphicsItem* graphicsItem = graphicsFromItem(_worldModel->item(index));
0337         if(graphicsItem) {
0338             removeItem(graphicsItem);
0339             delete graphicsItem;
0340         }
0341     }
0342 }
0343 
0344 void WorldScene::worldCurrentChanged(const QModelIndex& current, const QModelIndex& /*previous*/)
0345 {
0346     if(!_worldView || _worldView->viewport()->hasFocus()) return;
0347     QGraphicsItem* graphicsItem = graphicsFromItem(_worldModel->item(current));
0348     if(graphicsItem) graphicsItem->ensureVisible(QRectF(), 5, 5);
0349 }
0350 
0351 void WorldScene::worldSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
0352 {
0353     foreach(const QModelIndex &index, selected.indexes()) {
0354         QGraphicsItem* item = _itemsHash.value(_worldModel->item(index));
0355         if(item) item->setSelected(true);
0356     }
0357     foreach(const QModelIndex &index, deselected.indexes()) {
0358         QGraphicsItem* item = _itemsHash.value(_worldModel->item(index));
0359         if(item) item->setSelected(false);
0360     }
0361 }
0362 
0363 void WorldScene::worldDataChanged(bool dynamicOnly)
0364 {
0365     //if(dynamicOnly) return;
0366     _worldModel->simulationPause();
0367 
0368     if(!dynamicOnly) {
0369         /* Background */
0370         if(_bgColor != _worldModel->world()->color()) {
0371             _bgColor = _worldModel->world()->color();
0372             if(_bgColor == 0) setBackgroundBrush(Qt::NoBrush);
0373             else setBackgroundBrush(QBrush(QColor::fromRgba(_bgColor)));
0374         }
0375     }
0376 
0377     foreach (QGraphicsItem *item, items()) {
0378         StepGraphicsItem* gItem = dynamic_cast<StepGraphicsItem*>(item);
0379         if(gItem) {
0380             gItem->worldDataChanged(dynamicOnly);
0381         }
0382     }
0383     
0384     QRectF boundingRect = itemsBoundingRect();
0385     setSceneRect(boundingRect.united(QRectF(-20, -20, 40, 40)));
0386 }
0387 
0388 void WorldScene::updateViewScale()
0389 {
0390     if(_worldView) {
0391         _currentViewScale = _worldView->transform().m11();
0392         _worldModel->simulationPause();
0393         foreach (QGraphicsItem *item, items()) {
0394             StepGraphicsItem* gItem = dynamic_cast<StepGraphicsItem*>(item);
0395             if(gItem) gItem->viewScaleChanged();
0396         }
0397         if(_sceneAxes) _sceneAxes->viewScaleChanged();
0398     }
0399 }
0400 
0401 QRectF WorldScene::calcItemsBoundingRect()
0402 {
0403     QRectF boundingRect;
0404     foreach(QGraphicsItem* item, items()) {
0405         StepGraphicsItem* wItem = dynamic_cast<StepGraphicsItem*>(item);
0406         if(wItem) {
0407             boundingRect |= wItem->sceneBoundingRect();
0408             //qDebug() << itemFromGraphics(wItem)->name() << ": " << wItem->sceneBoundingRect() << endl;
0409         }
0410     }
0411     return boundingRect;
0412 }
0413 
0414 void WorldScene::messageLinkActivated(const QString& link)
0415 {
0416     emit linkActivated(QUrl::fromUserInput(link));
0417 }
0418 
0419 void WorldScene::settingsChanged()
0420 {
0421     worldModelReset();
0422     _messageFrame->raise();
0423 }
0424 
0425 void WorldScene::snapClear()
0426 {
0427     if(_snapItem) {
0428         _snapItem->setItemHighlighted(false);
0429         _snapItem = nullptr;
0430         _snapToolTip.clear();
0431         _snapTimer->start();
0432     }
0433 }
0434 
0435 StepCore::Item* WorldScene::snapHighlight(QPointF pos, SnapFlags flags, const SnapList* moreTypes)
0436 {
0437     SnapList types;
0438     if(flags.testFlag(SnapParticle)) types << StepCore::Particle::staticMetaObject();
0439     if(flags.testFlag(SnapRigidBody)) types << StepCore::RigidBody::staticMetaObject();
0440     if(moreTypes) types << *moreTypes;
0441 
0442     StepCore::Item* item = nullptr;
0443     QGraphicsItem* gItem = nullptr;
0444     foreach(gItem, items(pos)) {
0445         item = itemFromGraphics(gItem); if(!item) continue;
0446         if(flags.testFlag(SnapParticle) && item->metaObject()->inherits<StepCore::Particle>()) break;
0447         if(flags.testFlag(SnapRigidBody) && item->metaObject()->inherits<StepCore::RigidBody>()) break;
0448 
0449         if(moreTypes) {
0450             bool found = false;
0451             foreach(const StepCore::MetaObject* type, *moreTypes)
0452                 if(item->metaObject()->inherits(type)) { found = true; break; }
0453             if(found) break;
0454         }
0455         item = nullptr;
0456     }
0457 
0458     if(item) {
0459         if(_snapItem != gItem) {
0460             snapClear();
0461             _snapItem = static_cast<StepGraphicsItem*>(gItem);
0462             _snapItem->setItemHighlighted(true);
0463         }
0464         _snapPos = pos;
0465         _snapToolTip = _worldModel->formatNameFull(item);
0466         _snapTimer->start();
0467         return item;
0468 
0469     } else {
0470         snapClear();
0471         return nullptr;
0472     }
0473 }
0474 
0475 StepCore::Item* WorldScene::snapItem(QPointF pos, SnapFlags flags, const SnapList* moreTypes,
0476                                             int movingState, StepCore::Item* item, int num)
0477 {
0478     QString n;
0479     if(num >= 0) n = QString::number(num);
0480 
0481     _worldModel->simulationPause();
0482     StepCore::Item* sItem = snapHighlight(pos, flags, moreTypes);
0483 
0484     if(movingState == StepGraphicsItem::Started || movingState == StepGraphicsItem::Moving) {
0485         if(movingState == StepGraphicsItem::Started)
0486             _worldModel->setProperty(item, "body"+n,
0487                     QVariant::fromValue<StepCore::Object*>(NULL), WorldModel::UndoNoMerge);
0488 
0489         if(flags.testFlag(SnapSetPosition))
0490             _worldModel->setProperty(item, "position"+n,
0491                                 QVariant::fromValue(StepGraphicsItem::pointToVector(pos)));
0492 
0493         if(flags.testFlag(SnapSetLocalPosition))
0494             _worldModel->setProperty(item, "localPosition"+n,
0495                                 QVariant::fromValue(StepGraphicsItem::pointToVector(pos)));
0496 
0497         if(flags.testFlag(SnapSetAngle) && movingState == StepGraphicsItem::Started)
0498             _worldModel->setProperty(item, "angle"+n, QVariant::fromValue(0.0));
0499 
0500     } else if(movingState == StepGraphicsItem::Finished) {
0501         StepCore::Vector2d wPos(StepGraphicsItem::pointToVector(pos));
0502         StepCore::Vector2d lPos(0,0);
0503         double angle = 0.0;
0504 
0505         if(sItem) {
0506             if(sItem->metaObject()->inherits<StepCore::Particle>()) {
0507                 wPos = static_cast<StepCore::Particle*>(sItem)->position();
0508             } else if(sItem->metaObject()->inherits<StepCore::RigidBody>()) {
0509                 if(flags.testFlag(SnapOnCenter))
0510                     wPos = static_cast<StepCore::RigidBody*>(sItem)->position();
0511                 else
0512                     lPos = static_cast<StepCore::RigidBody*>(sItem)->pointWorldToLocal(wPos);
0513                 angle = static_cast<StepCore::RigidBody*>(sItem)->angle();
0514             }
0515 
0516         } else {
0517             lPos = wPos;
0518         }
0519 
0520         _worldModel->setProperty(item, "body"+n,
0521                     QVariant::fromValue<StepCore::Object*>(sItem), WorldModel::UndoNoMerge);
0522 
0523         if(flags.testFlag(SnapSetPosition))
0524             _worldModel->setProperty(item, "position"+n, QVariant::fromValue(wPos));
0525         if(flags.testFlag(SnapSetLocalPosition))
0526             _worldModel->setProperty(item, "localPosition"+n, QVariant::fromValue(lPos));
0527         if(flags.testFlag(SnapSetAngle))
0528             _worldModel->setProperty(item, "angle"+n, angle);
0529 
0530         snapClear();
0531     }
0532 
0533     return sItem;
0534 }
0535 
0536 void WorldScene::snapUpdateToolTip()
0537 {
0538     if(!_snapToolTip.isEmpty()) {
0539         QGraphicsView* view = views()[0];
0540         QPoint pos = view->viewport()->mapToGlobal(view->mapFromScene(_snapPos));
0541         QPoint size(1,1);
0542         QToolTip::showText(pos, _snapToolTip, view->viewport(), QRect(pos-size,pos+size));
0543     } else {
0544         QToolTip::hideText();
0545         // Hack to hide tooltip immediately
0546         QWheelEvent fakeEvent(QPointF(0,0), QPointF(0,0), QPoint(0, 0), QPoint(0, 0), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
0547         QCoreApplication::sendEvent(_messageFrame, &fakeEvent);
0548     }
0549 }
0550 
0551 bool WorldScene::hasItemCreator() const
0552 {
0553     return _itemCreator && !_itemCreator->finished();
0554 }
0555 
0556 WorldGraphicsView::WorldGraphicsView(WorldScene* worldScene, QWidget* parent)
0557     : QGraphicsView(worldScene, parent)
0558 {
0559     worldScene->_worldView = this;
0560     worldScene->_messageFrame->setParent(this);
0561     worldScene->_messageFrame->move(15,15);
0562     
0563     _sceneRect = worldScene->sceneRect();
0564     updateSceneRect();
0565     connect(worldScene, &QGraphicsScene::sceneRectChanged,
0566             this, &WorldGraphicsView::sceneRectChanged);
0567     
0568     //worldGraphicsView->setRenderHints(QPainter::Antialiasing);
0569     setDragMode(QGraphicsView::RubberBandDrag);
0570     //setDragMode(QGraphicsView::ScrollHandDrag);
0571     setResizeAnchor(QGraphicsView::AnchorViewCenter);
0572     #ifdef __GNUC__
0573     #warning Check paint() for all items to preserve painter state
0574     #warning Use NoViewportUpdate and manual updating here !
0575     #endif
0576     setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
0577     actualSize();
0578     settingsChanged();
0579 }
0580 
0581 void WorldGraphicsView::zoomIn()
0582 {
0583     scale(1.25, 1.25);
0584     updateSceneRect();
0585     
0586     static_cast<WorldScene*>(scene())->updateViewScale();
0587 }
0588 
0589 void WorldGraphicsView::zoomOut()
0590 {
0591     scale(1 / 1.25, 1 / 1.25);
0592     updateSceneRect();
0593     
0594     static_cast<WorldScene*>(scene())->updateViewScale();
0595 }
0596 
0597 void WorldGraphicsView::fitToPage()
0598 {
0599     QRectF br = static_cast<WorldScene*>(scene())->calcItemsBoundingRect();
0600     if(br.isNull())
0601         return;
0602     //qDebug() << br << " " << (br | QRectF(0,0,0,0)) << endl;
0603     QRect  ws = viewport()->rect();
0604 
0605     double currentViewScale = transform().m11();
0606     double s = qMin( ws.width()/br.width(), ws.height()/br.height() );
0607 
0608     // XXX: use QSize::scale !
0609 
0610     if(s < currentViewScale || s*0.8 > currentViewScale) {
0611         s *= 0.9;
0612         resetTransform();
0613         scale(s, -s);
0614         updateSceneRect();
0615     } else {
0616         s = currentViewScale;
0617     }
0618 
0619     centerOn(br.center());
0620 
0621     if(s != currentViewScale)
0622         static_cast<WorldScene*>(scene())->updateViewScale();
0623 }
0624 
0625 void WorldGraphicsView::actualSize()
0626 {
0627     resetTransform();
0628     scale(100, -100);
0629     updateSceneRect();
0630     
0631     centerOn(0, 0);
0632     
0633     static_cast<WorldScene*>(scene())->updateViewScale();
0634 }
0635 
0636 void WorldGraphicsView::settingsChanged()
0637 {
0638     if(qobject_cast<QOpenGLWidget*>(viewport())) {
0639         if(!Settings::enableOpenGL()) setViewport(new QWidget(this));
0640     } else {
0641         if(Settings::enableOpenGL()) {
0642             //qDebug() << "enable OpenGL" << endl;
0643             setViewport(new QOpenGLWidget(this));
0644             if(!qobject_cast<QOpenGLWidget*>(viewport())) {
0645                 qDebug() << "can't create QOpenGLWidget!" << Qt::endl;
0646             }
0647         }
0648     }
0649     if(scene()) static_cast<WorldScene*>(scene())->settingsChanged();
0650 }
0651 
0652 void WorldGraphicsView::mousePressEvent(QMouseEvent* e)
0653 {
0654     if(e->button() == Qt::MiddleButton) {
0655         setDragMode(QGraphicsView::ScrollHandDrag);
0656         QMouseEvent e1(e->type(), e->pos(), e->globalPos(), Qt::LeftButton,
0657                         e->buttons(), e->modifiers());
0658         QGraphicsView::mousePressEvent(&e1);
0659     } else {
0660         QGraphicsView::mousePressEvent(e);
0661     }
0662 }
0663 
0664 void WorldGraphicsView::mouseReleaseEvent(QMouseEvent* e)
0665 {
0666     QGraphicsView::mouseReleaseEvent(e);
0667     if(e->button() == Qt::MiddleButton) {
0668         setDragMode(QGraphicsView::RubberBandDrag);
0669     }
0670 }
0671 
0672 void WorldGraphicsView::wheelEvent(QWheelEvent* e)
0673 {
0674     if (e->modifiers() == Qt::ControlModifier) {
0675         if (e->angleDelta().y() == 0) {
0676             e->ignore();
0677             return;
0678         }
0679         
0680         QGraphicsView::ViewportAnchor anchor = transformationAnchor();
0681         setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
0682         if (e->angleDelta().y() > 0) {
0683             zoomIn();
0684         }
0685         else {
0686             zoomOut();
0687         }
0688         setTransformationAnchor(anchor);
0689         
0690         e->accept();
0691         return;
0692     }
0693     
0694     QGraphicsView::wheelEvent(e);
0695 }
0696 
0697 void WorldGraphicsView::scrollContentsBy(int dx, int dy)
0698 {
0699     QGraphicsView::scrollContentsBy(dx, dy);
0700     WorldSceneAxes* axes = static_cast<WorldScene*>(scene())->_sceneAxes;
0701     if(axes)
0702         axes->setPos(mapToScene(viewport()->width()/2, viewport()->height()/2));
0703         //axes->setPos(mapToScene(20, maximumViewportSize().height()-horizontalScrollBar()->height()-23));
0704 }
0705 
0706 void WorldGraphicsView::sceneRectChanged(const QRectF& rect)
0707 {
0708     _sceneRect = rect;
0709     updateSceneRect();
0710 }
0711 
0712 void WorldGraphicsView::updateSceneRect()
0713 {
0714     QPointF topleft = mapToScene(0, 0);
0715     QPointF bottomright = mapToScene(viewport()->width(), viewport()->height());
0716     
0717     QRectF viewportRect(topleft, bottomright);
0718     QRectF sceneRect = _sceneRect.adjusted(-viewportRect.width() / 4,
0719                                            viewportRect.height() / 4,
0720                                            viewportRect.width() / 4,
0721                                            -viewportRect.height() / 4);
0722     setSceneRect(sceneRect.united(viewportRect));
0723 }
0724 
0725 #include "moc_worldscene.cpp"